2.1概述
概念
- 异常处理的抓抛模型
- 异常类对象的生成
- 由虚拟机自动生成,自动抛出异常
- 由开发人员手动创建,手动抛出异常
- 如果一个方法内抛出异常,该异常对象会被抛给调用者方法中处理。
如果异常没有在调用者方法里处理,它继续被抛给这个调用方法的上层方法。
这个过程将一起继续下去,直到异常被。这个过程被称为捕获异常(catch) - 如果一个异常回到main()方法,并且main()也不处理,则程序运行终止
- 程序员通常只能处理Exception,而对Error无能为力
Java异常处理的五个关键字:try、catch、finally、throw、throws
如何处理异常
- 抛—执行代码时,一旦出现异常,就会在异常的代码处理生成一个应对的异常类的对象,并将此对象抛出(分为自动抛出、手动抛出)
- 一旦抛出此异常类的对象,程序就终止执行
- 此异常类的对象抛给方法的调用者(java运行时系统)
- 抓—抓住上一步抛出的异常类的对象。如何抓取
- 处理方式
- 异常处理方式一:抓取异常(捕获异常)try-catch-finally
- 异常处理方式二:声明抛出异常throws
2.2处理方式一:抓取异常
try-catch-finally
try {
// 可能出现异常的代码
} catch(Exception1 e) {
// 异常1处理方法
} catch(Exception2 e) {
// 异常2处理方法
} catch(Exception3 | Exception4 | Exception5 e) {
// 异常2处理方法
e.printStackTrace();
} finally {
// 一定要执行的代码
}
注意
- finally是可选的
- try 块内声明的变量为局部变量。出了try { }就不能被调用了
- catch 语句内对异常的处理
- getMessage() — 返回String关键错误信息
- printStackTrace() — 打印异常类名和异常信息,以及异常出现在程序中的位置。返回值void
- 可以多个catch语句,try中抛出的异常类对象从上往下匹配catch中的异常类的类型,一旦匹配就执行catch中的代码 执行完就跳出后面的catch语句
- 如果异常处理了,其后的代码继续执行
- 对于运行时异常,可以不显式的进行处理;对于编译时异常,必须要显式的进行处理
- 若catch中多个异常类型是”并列”关系,哪个在上都可以 若catch中多个异常类型是”包含”关系,必须子类异常类放在父类异常类的上面进行处理,否则编译报错。
- finally中的语句一定会被执行。不管try、catch中是否仍有异常未被处理,以及是否有return语句,除了是明确指定退出程序外,如System.exit(1)
- try-catch可以嵌套
- 一个catch抓取多个异常时,多个异常类型之间用 “|” 分隔
- Exception1 - Exception5:异常对应的类
2.3处理方式二:声明抛出异常
当一个方法产生一个它不处理的异常时,那么就需要在该方法的头部声明这个异常,以便将该异常传递到方法的外部进行处理。使用 throws 声明的方法表示此方法不处理异常。throws 具体格式如下:
returnType method_name(paramList) throws Exception 1,Exception2,…{…}
其中,returnType 表示返回值类型;method_name 表示方法名;paramList 表示参数列表;Exception 1,Exception2,… 表示异常类。
如果有多个异常类,它们之间用逗号分隔。这些异常类可以是方法中调用了可能拋出异常的方法而产生的异常,也可以是方法体中生成并拋出的异常。
使用 throws 声明抛出异常的思路是,当前方法不知道如何处理这种类型的异常,该异常应该由向上一级的调用者处理;如果 main 方法也不知道如何处理这种类型的异常,也可以使用 throws 声明抛出异常,该异常将交给 JVM 处理。JVM 对异常的处理方法是,打印异常的跟踪栈信息,并中止程序运行,这就是前面程序在遇到异常后自动结束的原因。
手动抛出异常throw
在编写程序时,我们必须要考虑程序出现问题的情况。比如,在定义方法时,方法需要接受参数。那么,当调用方法使用接受到的参数时,首先需要先对参数数据进行合法的判断,数据若不合法,就应该告诉调用者,传递合法的数据进来。这时需要使用抛出异常的方式来告诉调用者。
在java中,提供了一个throw关键字,它用来抛出一个指定的异常对象。那么,抛出一个异常具体如何操作呢?
- 创建一个异常对象。封装一些提示信息(信息可以自己编写)。
- 需要将这个异常对象告知给调用者。怎么告知呢?怎么将这个异常对象传递到调用者处呢?通过关键字throw就可以完成。throw 异常对象。
throw用在方法内,用来抛出一个异常对象,将这个异常对象传递到调用者处,并结束当前方法的执行。
使用格式:
throw new 异常类名(参数);
例如:
throw new NullPointerException("要访问的arr数组不存在");
throw new ArrayIndexOutOfBoundsException("该索引在数组中不存在,已超出范围");
学习完抛出异常的格式后,我们通过下面程序演示下throw的使用。
public class ThrowDemo {
public static void main(String[] args) {
//创建一个数组
int[] arr = {2,4,52,2};
//根据索引找对应的元素
int index = 4;
int element = getElement(arr, index);
System.out.println(element);
System.out.println("over");
}
/*
* 根据 索引找到数组中对应的元素
*/
public static int getElement(int[] arr,int index){
//判断 索引是否越界
if(index<0 || index>arr.length-1){
/*
判断条件如果满足,当执行完throw抛出异常对象后,方法已经无法继续运算。
这时就会结束当前方法的执行,并将异常告知给调用者。这时就需要通过异常来解决。
*/
throw new ArrayIndexOutOfBoundsException("哥们,角标越界了~~~");
}
int element = arr[index];
return element;
}
}
注意:如果产生了问题,我们就会throw将问题描述类即异常进行抛出,也就是将问题返回给该方法的调用者。
那么对于调用者来说,该怎么处理呢?一种是进行捕获处理,另一种就是继续讲问题声明出去,使用throws声明处理。
声明异常throws
声明异常:将问题标识出来,报告给调用者。如果方法内通过throw抛出了编译时异常,而没有捕获处理(稍后讲解该方式),那么必须通过throws进行声明,让调用者去处理。
关键字throws运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常).
声明异常格式:
修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2…{ }
声明异常的代码演示:
public class ThrowsDemo {
public static void main(String[] args) throws FileNotFoundException {
read("a.txt");
}
// 如果定义功能时有问题发生需要报告给调用者。可以通过在方法上使用throws关键字进行声明
public static void read(String path) throws FileNotFoundException {
if (!path.equals("a.txt")) {//如果不是 a.txt这个文件
// 我假设 如果不是 a.txt 认为 该文件不存在 是一个错误 也就是异常 throw
throw new FileNotFoundException("文件不存在");
}
}
}
throws用于进行异常类的声明,若该方法可能有多种异常情况产生,那么在throws后面可以写多个异常类,用逗号隔开。
public class ThrowsDemo2 {
public static void main(String[] args) throws IOException {
read("a.txt");
}
public static void read(String path)throws FileNotFoundException, IOException {
if (!path.equals("a.txt")) {//如果不是 a.txt这个文件
// 我假设 如果不是 a.txt 认为 该文件不存在 是一个错误 也就是异常 throw
throw new FileNotFoundException("文件不存在");
}
if (!path.equals("b.txt")) {
throw new IOException();
}
}
}
2.4 异常注意事项
- 多个异常使用捕获又该如何处理呢?
- 多个异常分别处理。
- 多个异常一次捕获,多次处理。
- 多个异常一次捕获一次处理。
一般我们是使用一次捕获多次处理方式,格式如下:
try{
编写可能会出现异常的代码
}catch(异常类型A e){ 当try中出现A类型异常,就用该catch来捕获.
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}catch(异常类型B e){ 当try中出现B类型异常,就用该catch来捕获.
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}
注意:这种异常处理方式,要求多个catch中的异常不能相同,并且若catch中的多个异常之间有子父类异常的关系,那么子类异常要求在上面的catch处理,父类异常在下面的catch处理。
- 运行时异常被抛出可以不处理。即不捕获也不声明抛出。
- 如果finally有return语句,永远返回finally中的结果,避免该情况.
- 如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异常。
- 父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常。此时子类产生该异常,只能捕获处理,不能声明抛出