异常体系结构
Throwable:Error 和 Exception 类的父类
Error:代表的系统级别错误(属于严重问题),系统一旦出现问题,sun公司会把这些问题封装成Error对象给出来
Exception:异常,是指在程序的运行过程中所发生的不正常的事件,它会中断正在运行的程序。程序员通常用Exception 及其子类来封装程序出现的问题
- 运行时异常:
RuntimeException
及其子类,编译阶段不会出现错误提醒,运行时出现的异常 不要求必须捕获或者声明抛出(如:数组索引越界异常) - 编译时异常:Checked异常 编译阶段出现错误提醒 要求必须捕获或者声明抛出(如:日期解析异常)
- 异常处理:Java 编程语言使用异常处理机制为程序提供了错误处理的能力
程序中预先设置好对付异常的处理办法 —程序运行—> 异常 —异常处理—> 处理完毕,程序继续运行
Java 的异常处理是通过5个关键字来实现的:try、catch、 finally、throw、throws
捕获异常 | 声明异常 | 抛出异常 | |
---|---|---|---|
try | 执行可能产生异常的代码 | throws | throw |
catch | 捕获异常 | 声明方法可能要抛出的各种异常 | 手动抛出异常 |
finally | 无论是否发生异常,代码总能执行 |
try-catch
第一种情况:正常情况
public void method(){
👉 try {
// 代码段(此处不会产生异常)
} catch (异常类型 ex) {
// 对异常进行处理的代码段
}
👉 // 代码段
}
第二种情况:出现异常
public void method(){
try {
👉 // 代码段 1
👉 // 产生异常的代码段 2
// 代码段 3
👉 } catch (异常类型 ex) {
👉 // 对异常进行处理的代码段4
}
👉 // 代码段5
}
try —发生异常—> 产生异常对象 —> 异常类型匹配 —进入catch块—> catch —程序继续执行—> try-catch块后的代码段
printStackTrace()
的堆栈跟踪功能显示出程序运行到当前类的执行流程
// 异常堆栈信息
java.util.InputMismatchException // 异常类型
at java.util.Scanner.throwFor(Scanner.java:840)
at java.util.Scanner.next(Scanner.java:1461)
at java.util.Scanner.nextInt(Scanner.java:2091)
at java.util.Scanner.nextInt(Scanner.java:2050)
at cn.jbit.exception.Test3.main(Test3.java:15)
// 在main方法中抛出了异常 出现异常的位置第15行
第三种情况:异常类型不匹配
public void method(){
try {
👉 // 代码段 1
👉 // 产生异常的代码段 2
// 代码段 3
👉 } catch (异常类型 ex) {
// 对异常进行处理的代码段4
}
// 代码段5
}
try —发生异常—> 产生异常对象 —> 异常类型不匹配 ------>程序中断运行
-
在catch块中处理异常。加入用户自定义处理信息
System.err.println("出现错误:被除数和除数必须是整数");
-
调用方法输出异常信息
e.printStackTrace();
-
异常对象常用的方法
方法 说明 void printStackTrace() 输出异常的堆栈信息 String getMessage() 返回异常信息描述字符串,是 printStackTrace()
输出信息的一部分
常见的异常类型
异常类型 | 说明 |
---|---|
Exception | 异常层次结构的父类 |
ArithmeticException | 算术错误情形,如以零作除数 |
ArrayIndexOutOfBoundsException | 数组下标越界 |
NullPointerException | 尝试访问null 对象成员 |
ClassNotFoundException | 不能加载所需的类 |
lllegalArgumentException | 方法接收到非法参数 |
ClassCastException | 对象强制类型转换出错 |
NumberFormatException | 数字格式转换异常,如把"abc"转换成数字 |
try-catch-finally
try-catch 块后加入finally 块,不论是否发生异常都执行
不执行的唯一情况
try 块 (有异常)
catch 块
System.exit(1)
finally 块
//无异常,中断程序,退出Java虚拟机
当 try-catch-finally
结构中存在 return
语句时,执行顺序如下:
1、执行 try
块:
- 如果
try
块中有return
语句,方法将准备返回值,但返回过程尚未完成。
2、执行 finally
块:
- 无论
try
块中是否发生异常,finally
块都会执行。在finally
块执行期间,return
语句的处理会被挂起。
3、完成返回操作:
- 如果
finally
块中有return
语句,它会覆盖try
或catch
块中的返回值。 - 如果
finally
块没有return
语句,则方法会返回try
或catch
块中的返回值。
catch块中有return 语句执行过程与此类似
try-catch-finally 结构中try 语句块是必须的,catch、finally语句块均可选,但两者至少出现之一
多重catch块
引发多种类型的异常
-
排列catch 语句的顺序:先子类后父类
-
发生异常时按顺序逐个匹配
-
只执行第一个与异常类型匹配的catch语句
throw | throws |
---|---|
生成并抛出异常 | 声明方法内抛出了异常 |
位于方法体内部,可作为单独语句使用 | 必须跟在方法参数列表后面,不能单独使用 |
抛出一个异常对象,且只能是一个 | 声明抛出异常类型,可以跟多个异常 |
抛出异常
使用关键字 throws
抛出异常,多个异常使用逗号隔开。在最外层统一处理异常。
public Object findById() throws NullPointerException,ArrayIndexOutofBoundsException,ClassCastException{
return null;
}
声明异常
使用 throw
关键字
throw new 异常对象("错误信息")
throw new AgeRangeException("年龄不合法!");
自定义异常
当 JDK 中的异常类型不能满足程序的需要时,可以自定义异常类
使用自定义异常的步骤
定义异常类:继承 Throwable 类、继承 Excepion 或者 RuntimeException
public class AgeRangeException extends Exception{
public AgeRangeException(String message) {
super(message);
}
}
A方法调用B方法时,B方法却抛出了异常。那A方法继续抛出原有的异常还是抛出一个新异常呢?
-
抛出原有的异常:A方法与B方法进行了关联,不便于代码的修改和扩展
-
抛出新的异常:异常链创建了新的异常但却保留了原有异常的信息
案例
要求1:在 setAge(int age) 中对年龄进行判断,如果年龄介于1到100直接赋值,否则抛出异常
要求2:在测试类中创建对象并调用 setAge(int age) 方法,使用 try-catch 捕获并处理异常
public class AgeRangeException extends Exception{
public AgeRangeException(String message) {
super(message);
}}
public class Test2 {
private int age;
public void setAge(int age) throws AgeRangeException{
if(age > 0 && age < 101){
this.age = age;
} else {
throw new AgeRangeException("年龄不合法!");
}
}
public static void main(String[] args) {
Test2 t = new Test2();
try {
t.setAge(24);
t.setAge(101);
}catch (AgeRangeException ex) {
System.out.println(ex.getMessage());
}}}