1. Java异常体系
Error类: 是指Java运行时的内部错误或者资源耗尽错误, 必须由程序员自己解决
Exception类: 可以由程序自己解决
关于异常, 有分为以下两种:
- 运行时异常 / 非受查异常: 在程序运行时跑出的异常
- 编译时异常 / 受查异常: 在程序编译时的异常
2. 处理异常的方式
处理异常的方式有两种:
- LBYL: 在操作之前做充分的检查
2. EAFP: 先操作, 遇到问题再处理
通常情况下, 我们经常会使用到第二种方式来处理异常.
3. 异常的基本用法
通常情况下, 我们会使用 try catch方法来捕捉异常
try {
// 可能出现异常的语句
} catch (异常的类型 引用) {
// 出现异常后的处理行为
} finally {
// 异常的出口, 常用来处理善后工作
}
如果不处理异常, 一旦发生异常后, 就会将程序交由JVM处理, 这时, 程序会立即停止, 不再继续执行. 因此, world就没有被打印
如果处理了异常, 一旦 try 中出现异常, 那么 try 代码块中的程序就不会继续执行, 而是交给 catch 中的代码来执行. catch 执行完毕会继续往下执行. 因此我们可以看出, 打印出了world
由上图我们可以看出, 在catch块捕捉到了异常之后, 我们使用了e.printStackTrace() 方法来查看出现异常代码的调用栈
4. try catch语句使用时的注意事项
-
catch只能处理对应种类的异常
由于出现的异常是算数异常而非数组下标越界异常, 所以catch无法捕捉到这个异常
-
catch可以有多个
-
也可以用一个catch捕获多种异常(不推荐)
-
不建议直接捕获 Exception
-
finally 表示最后的善后工作, 例如释放资源
-
finally中的程序, 无论如何都会执行
-
不建议在 finally 语句中出现 return 语句
5. 调用异常的流程:
- 程序先执行 try 中的代码
- 如果 try 中的代码出现异常, 就会结束 try 中的代码, 看和 catch 中的异常类型是否匹配.
- 如果找到匹配的异常类型, 就会执行 catch 中的代码
- 如果没有找到匹配的异常类型, 就会将异常向上传递到上层调用者.
- 如果上层调用者也没有处理的了异常, 就继续向上传递.
- 一直到 main 方法也没有合适的代码处理异常, 就会交给 JVM 来进行处理, 此时程序就会异常终止
- 无论是否找到匹配的异常类型, finally 中的代码都会被执行到(在该方法结束之前执行).
6. 抛出异常
通过 throw 关键字来抛出一个异常
public static void main(String[] args) {
int a = 10;
if(a == 10) {
throw new RuntimeException("a == 10");
}
}
7. 异常的声明
我们在对异常进行处理的时候, 如果能知道异常会在哪里出现, 就可以有效的进行异常捕获.
因此, 我们可以对异常进行声明
通过 throw 关键字, 把可能抛出的异常显示的标注在方法的定义位置.
public static int func(int a, int b) throws ArithmeticException {
if(b == 0) {
throw new ArithmeticException("b == 0");
}
return a / b;
}
8. 如果出现的异常为受查异常(编译时异常), 一定要进行显示的处理
class Person implements Cloneable{
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class TestDemo {
public static void main(String[] args) {
Person person = new Person();
try {
Person person1 = (Person) person.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
9. 自定义异常类
自定义一个异常类, 必须要继承一个父类异常
class MyException extends RuntimeException {
public MyException(String message) {
super(message);
}
}
public class TestDemo {
public static void func(int x, int y) throws MyException {
if(y == 0) {
throw new MyException("y == 0");
}
System.out.println(x / y);
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int x = scanner.nextInt();
int y = scanner.nextInt();
func(x, y);
}
}
注意:
- 自定义异常通常会继承Exception 或者 RunTimeException
- 继承 Exception 的异常默认是受查异常
- 继承 RunTimeException 默认是非受查异常