一、异常体系
:::
- 异常体系
- 程序在执行过程中,可能会发生各种各样的不正常情况,因此就需要很多的“异常类”来封装和描述这些不正常的情况,我们对这个“异常类”进行向上提取,就得到了异常的体系
- 异常体系的概述:
- 所有不正常情况的老祖宗类为 Throwable类,在Throwable类中又有Error(错误)和Exception(异常)两个重要的子类
- Error (错误)类,指的就是“资源耗尽错误”或“虚拟机内部错误”等问题。如果开发中遇到了这类错误,我们在不结束程序的前提下是无法解决的。只能修改代码或重新安装虚拟机后,再运行程序
Exception (异常) 类,值得就是开发中遇到的异常,这个需要开发者尽力去解决,因为异常是可以解决的不正常情况 :::info
二、异常的分类
:::
异常有那些分类?
- 编译时异常:RuntimeException类及其所有子类。强制我们处理
- 运行时异常:Exception类及其所有子类。不强制我们处理
- 声明异常的处理方式:throws
- 声明异常是“消极”的处理方式,本质上没有解决异常
- 捕捉异常的处理方式: try…catch…finally
- 捕捉异常属于“积极”的处理方式,从根本上已经处理了异常
- 关于不正常情况的分类:
不可检查异常 UnCheckedException
—->运行时异常和Error,程序在编译时期,无法检查到程序中(运行中)出现的不正常情况
可检查异常 CheckedException
—->程序在编译时期,可以检查出程序中出现的不正常情况 :::info
三、声明异常 throws
:::
- 我们需要处理哪些异常?
编译时**的异常我们必须处理,否则会发生编译错误,运行时的异常我们可以处理,也可以选择不处理**
—->这是在编译时,对代码异常的处理,这个时候代码还没有运行。
无论出现那种异常,我们最终都必须处理,否则最后异常会被抛给虚拟机,造成程序的终止。
—->这在代码运行时,无论什么异常,如果不处理,都会造成程序的终止
- 如何声明异常呢?
- 当方法体中可能出现异常,此时我们又无法处理该异常,就可以把方法中出现的异常声明出来,也就是在方法声明的末尾把方法中可能出现的异常使用**throws关键字**声明出来,然后报告给方法的调用者,交给方法的调用者来处理
- 声明异常的语法:
- 使用“声明异常”时,我们可以在throws 关键字末尾 声明多个“异常类”
注意**:“声明异常”属于消极的处理方式,本质上并没有解决方法体中可能出现的异常。只是把异常声明出来,报告给方法的上层调用者,交给方法的调用者来处理。** :::info[修饰符] 返回值类型 方法名(形参列表) throws 异常类1, 异常类2, 异常类3, ... {
// 方法体
return [返回值];
}
四、throw和throws的区别
::: 面试题:请问throw和throws有什么区别?
- 使用位置区别
- throw:必须在“方法体”使用
- throws:必须在“方法声明末尾”使用
- 操作内容区别
- throw:操作的是“异常对象”,只能操作“一个”异常对象
- throws:操作的是“异常类”,可以操作“多个”异常类
- 本质上的区别:
- throw: 抛出异常,一旦执行了throw概念句子,一定会抛出一个异常
throws:声明异常,方法末尾使用了throws关键字,方法体中未必会抛出异常
public class Test02 {
// 根据索引获得元素值
public static int getValue(int[] arr, int index)
throws NullPointerException, ArrayIndexOutOfBoundsException {
// 处理arr取值为null的情况
if (arr == null) {
throw new NullPointerException("空指针异常,arr:" + arr);
}
// 处理index取值不合法的情况
if (index < 0 || index >= arr.length) {
// 需求:如果index取值不合法,则抛出数组索引越界异常!
throw new ArrayIndexOutOfBoundsException("数组索引越界异常,index:" + index);
}
// 执行到此处,则证明index取值合法
int value = arr[index];
return value;
}
public static void main(String[] args)
throws StudentAgeOutOfBoundsException {
// 注意:在此处,我们就可以处理该异常,但是“捕捉异常”还未学习,因此暂时使用“声明异常”来处理
Student stu = new Student("卧龙", -18);
System.out.println(stu);
}
}
//输出:
Exception in thread "main" com.bjpowernode.p2.exception.StudentAgeOutOfBoundsException: 学生年龄越界异常,age:-18
at com.bjpowernode.p2.exception.Student.setAge(Student.java:33)
at com.bjpowernode.p2.exception.Student.<init>(Student.java:13)
at com.bjpowernode.p2.exception.Test02.main(Test02.java:44)
五、捕捉异常 try…catch…finally
:::
- 我们需要处理哪些异常?
编译时**的异常我们必须处理,否则会发生编译错误,运行时的异常我们可以处理,也可以选择不处理**
—->这是在编译时,对代码异常的处理,这个时候代码还没有运行。
- 什么是捕捉异常?
- 捕捉异常的特点:捕捉异常属于“积极”的处理方式,本质上已经解决了异常的情况
- 使用情况:如果方法体中可能出现异常,此时我们又能解决该异常,就使用捕捉异常来解决
- 捕捉异常的多种组合
try…catch组合:
try {
// 书写可能出现异常的代码
}
catch (异常类 对象) {
// 用于处理捕获到的异常
}
try…多catch组合:这个语法可以对代码块中出现的异常做出“针对性”的处理。**使用时,子类异常catch必须放在父类异常的catch前面**
try {
* // 书写可能出现异常的代码
* }
* catch (异常类1 对象) {
* // 用于处理捕获到的异常
* }
* catch (异常类2 对象) {
* // 用于处理捕获到的异常
* }
* ......更多的catch(){}
try…多catch…finally组合:在这个语法中,即使在try或catch中执行了return操作,finally代码块中的代码还是会执行。**在开发中,经常在finally代码块中执行“关闭资源的操作”**,例如:关闭IO流、关闭数据库连接等等操作。
try {
* // 书写可能出现异常的代码
* }
* catch (异常类1 对象) {
* // 用于处理捕获到的异常
* }
* catch (异常类2 对象) {
* // 用于处理捕获到的异常
* }
* ......
* finally {
* // 无论try中是否发生异常,则都会执行finally中的代码!
* }