异常 :指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止。
在Java等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常对象并抛出了一个异常对象。Java处理异常的方式是中断处理。
异常体系
异常的根类是 java.lang.Throwable ,其下有两个子类: java.lang.Error 与 java.lang.Exception
Throwable体系:
- Error:严重错误,无法通过处理的错误,只能事先避免。
- Exception:表示异常,异常产生后程序员可以通过代码的方式纠正,使程序继续运行,是必须要处理的。
- RuntimeException是Exception的子类
Throwable中的常用方法
// 打印异常的详细信息。包含了异常的类型,异常的原因,
// 还包括异常出现的位置,在开发和调试阶段,都得使用printStackTrace。
void printStackTrace()
// 获取发生异常的原因。 提示给用户的时候,就提示错误原因。
String getMessage()
处理异常
throw
package com;
public class Test {
public static void main(String[] args) {
int[] array = {1, 2, 3};
int value = getValue(array, 4);
System.out.println(value);
}
static int getValue(int[] array, int index) {
if (index < 0 || index > array.length - 1){
// throw的异常对象只能写一个
throw new ArrayIndexOutOfBoundsException("数组越界了");
}
System.out.println("throw之后的代码不会继续执行了");
return array[index];
}
}
throws
package com;
import java.sql.SQLException;
public class Test {
public static void main(String[] args) throws Exception {
int[] array = {1, 2, 3};
int value = getValue(array, 4);
System.out.println(value);
}
// throws 可以抛出多个异常类
static int getValue(int[] array, int index) throws ArrayIndexOutOfBoundsException,SQLException {
return array[index];
}
}
try catch
package com;
import java.io.IOException;
import java.sql.SQLException;
import java.text.ParseException;
public class Test {
public static void main(String[] args) throws Exception {
int[] array = {1, 2, 3};
int value = getValue(array, 4);
System.out.println(value);
}
static int getValue(int[] array, int index) {
int i = 0;
try {
i = array[index];
// 可以多catch使用
} catch (ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
}catch (NullPointerException e) {
e.printStackTrace();
} finally {
System.out.println("无论如何都会执行的代码");
}
return i;
}
}
try catch finally/resource
JAVA的一大特性就是JVM会对内部资源实现自动回收,即自动GC,给开发者带来了极大的便利。但是JVM对外部资源
的引用却无法自动回收,例如数据库连接,网络连接以及输入输出IO流等,这些连接就需要我们手动去关闭,不然会导致外部资源泄露,连接池溢出以及文件被异常占用等。
try catch finally
传统的手动释放外部资源一般放在一般放在try{}catch(){}finally{}机制的finally代码块中,因为finally代码块中语句是肯定会被执行的,即保证了外部资源最后一定会被释放。同时考虑到finally代码块中也有可能出现异常,finally代码块中也有一个try{}catch(){},这种写法是经典的传统释放外部资源方法,显然是非常繁琐的。
public static void main(String[] args) {
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream("test");
System.out.println(fileInputStream.read());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
try catch resource
JDK1.7之后有了try-with-resource处理机制。首先被自动关闭的资源需要实现Closeable或者AutoCloseable接口,因为只有实现了这两个接口才可以自动调用close()方法去自动关闭资源。
写法为try(){}catch(){},将要关闭的外部资源在try()中创建,catch()捕获处理异常。
其实try-with-resource机制是一种语法糖,其底层实现原理仍然是try{}catch(){}finally{}写法,不过在catch(){}代码块中有一个addSuppressed()方法,即异常抑制方法。如果业务处理和关闭连接都出现了异常,业务处理的异常会抑制关闭连接的异常,只抛出处理中的异常,仍然可以通过getSuppressed()方法获得关闭连接的异常。
public static void main(String[] args) {
try(FileInputStream fileInputStream = new FileInputStream("test")) {
System.out.println(fileInputStream.read());
} catch (IOException e) {
e.getSuppressed();
e.printStackTrace();
}
}
两种异常处理的区别
如果希望产生异常后 ,方法停止运行,就用throw或throws
如果希望产生异常后 ,方法可以继续运行,就用try catch
异常注意事项
-
如果父类抛出多个异常,子类覆盖父类方法时,只能抛出相同的异常或者他的子集。
-
父类方法没有抛出异常,子类覆盖父类该方法时也不可抛出异常。此时子类对异常,只能捕获处理,不能声明抛出。
-
在多异常捕获处理时,前边的类不能是后边的类的父类
-
finally代码块一定会被执行,通常用于资源回收
自定义异常
自定义的是编译时期的异常:继承Exception
自定义的是运行时期的异常:继承RuntimeException
自定义基础异常
package com.lxit.testnginx.testnginx;
import org.springframework.http.HttpStatus;
/**
*基础异常,谁定义异常就继承它
*/
public class BasicException extends RuntimeException {
/**
* 错误状态码
* spring-boot
* package org.springframework.http;
* public enum HttpStatus {
* OK(200, "OK"),
*/
private HttpStatus status;
public BasicException(String message, HttpStatus status) {
super(message);
this.status = status;
}
public HttpStatus getStatus() {
return status;
}
public void setStatus(HttpStatus status) {
this.status = status;
}
}
使用自定义基础异常
package com.lxit.testnginx.testnginx;
import org.springframework.http.HttpStatus;
public class FileStorageException extends BasicException {
public FileStorageException(String message) {
super(message, HttpStatus.NOT_FOUND);
}
}
测试
package com.lxit.testnginx.testnginx;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpStatus;
@SpringBootTest
class TestnginxApplicationTests {
@Test
void contextLoads() {
String s = null;
if (s == null){
FileStorageException fileStorageException = new FileStorageException("文件找不到异常");
// 404 NOT_FOUND
System.out.println(fileStorageException.getStatus());
throw fileStorageException;
}
}
}
面试题
try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后?
package com.example.javasestudy.exception;
public class TryCatchReturn {
public static void main(String[] args) {
// finally 在 return之后执行
// 如果finally中也有return,那么返回值就是finally中的return
System.out.println(test());
}
public static int test(){
int x = 1;
try{
return x;
}finally {
++x;
}
}
}
常见的runtime expection
NullPointerException - 空指针引用异常
ClassCastException - 类型强制转换异常。
ArithmeticException - 算术运算异常
IndexOutOfBoundsException - 下标越界异常
SQLException:操作数据库异常
IOException:输入输出异常
新的淤青是茄子绀或虾红色,旧的淤青是狐狸或貂毛,老茶的颜色。
房思琪的初恋乐园
林奕含