Java 异常
一、异常简述
1.异常的三种类型
- 检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
- 运行时异常: 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
- 错误: 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。
2.异常的层次结构
Throwable 类是 Java 语言中所有错误(Error)或异常(Exception)的超类。
- Error:程序所发生的的错误,无法处理,是能避免。
- Exception:主要有 IOException 类和 RuntimeException 类两个子类。
3.了解异常处理
错误:只能通过修改源代码解决
//OutOfMemoryError: Java heap space 内存溢出错误
int arr[] = new int[1024*1024*1024];
异常:可以进行特定的处理,使程序继续运行
1.使用 throw 关键字处理
2.使用 throws 关键字,在方法声明时抛出异常
3.使用 try catch finally 关键字,捕获抛出异常
二、异常的处理
1.Java异常处理过程
1.JVM遇到异常会
创建异常对象
(对象内容包括:内容、原因、位置)
2.寻找 try catch 或者方法的 throws异常抛出
,如果没有异常抛出,则直接交给JVM进行处理
3.JVM根据接收到的异常信息在控制台进行打印
,如果没有异常抛出,则终止程序
一个简单的异常程序举例
2.异常的处理
throw关键字
作用
抛出异常
格式
throw new xxxException("异常产生的原因")
代码实例
//定义一个空数组
int[] arr = null;
//判断数组是否为空
if(arr == null){
//如果 if 判断成立,则使用 throw 关键字抛出异常
throw new NullPointerException("数组传递过来为空");
}
//定义一个长度为 5 的数组
int[] arr = new int[5];
//设置 arr 数组的一个索引值
int index = 5;
//判断数组索引是否越界
if(index < 0 || index > arr.length - 1 ){
//如果 if 判断成立,则使用 throw 关键字抛出异常
throw new ArrayIndexOutOfBoundsException("数组索引越界了");
}
注意事项
1.throw关键字必须
写在方法的内部
2.throw关键字后边new的对象必须是Exception或者Exception子类对象
3.throw关键字抛出指定异常对象,我们必须处理这个异常对象
- 如果创建的是RuntimeException或者是RuntimeException的子类对象,可以默认不处理,交给JVM(打印异常,终止程序)
- 如果创建的是编译异常(写代码时报错),必须处理这个异常
throws关键字
作用
方法内部抛出异常对象的时候,是必须处理这个异常对象的。
可以使用throws关键字处理异常对象,会把异常对象声明抛出给方法的调用者处理(自己不处理,给别人处理),最终交给JVM处理 → 中断处理。
格式
修饰符 返回值类型 方法名(参数列表) throws xxxExcepiton, yyyExcepiton, ...{
throw new xxxExcepiton("xxx异常产生原因");
throw new yyyExcepiton("yyy异常产生原因");
...
}
代码实例
public void test() throws /*FileNotFoundException*/ IOException{
/*
FileNotFoundException extends IOException
如果抛出的多个异常对象有子父类关系,那么直接声明父类异常即可
*/
//定义一个目标文件路径
String file = "c:\\exception.txt";
//传递 c:\error.txt 与目标文件路径比较
if(!file.equals("c:\\error.txt")) {
throw new FileNotFoundException("文件路径不是c:\\exception.txt");
}
//传递 c:\exception.doc 与目标文件路径比较
if(!file.endsWith("c:\\exception.doc")){
throw new IOException("文件的后缀名不是.txt");
}
}
注意事项
1.throws关键字
必须写在方法声明处
2.throws关键字后边声明的异常必须是Exception或者是Exception的子类
3.方法内部如果抛出了多个异常对象,那么throws后边必须也声明多个异常
- 如果
抛出的多个异常对象有子父类关系
,那么直接声明父类异常即可
4.调用了一个声明抛出异常的方法,必须的处理声明的异常
- 要么继续使用throws声明抛出,交给方法的调用者处理,最终交给JVM
- 要么try…catch处理异常
try catch finally关键字
try:捕获异常。
catch:处理异常。
finally:不论是否发生异常,都会执行 finally块 的内容。
作用
方法内部抛出异常对象的时候,是必须处理这个异常对象的。
可以使用 try catch 关键字捕获、处理
异常对象,由程序员根据情况处理。
格式
catch 块的数量是由 try 语句捕获的异常数量决定的
,大多数情况只有一个 catch块。
finally 块可有可无
。
try{
可能产生异常的代码
}catch(异常类名 变量名){
异常的处理逻辑,异常异常对象之后,怎么处理异常对象
一般在工作中,会把异常的信息记录到一个日志中
}
...
catch(异常类名 变量名){
...
}finally{
无论是否出现异常都会执行
}
代码实例
public class DemoTryCatchFinally {
public static void main(String[] args) {
//定义一个目标文件路径
String file = "c:\\exception.txt";
try {
//传递 c:\error.txt 与目标文件路径比较
if(!file.equals("c:\\error.txt")) {
throw new FileNotFoundException("文件路径不是c:\\exception.txt");
}
} catch (IOException e) {
//异常的处理逻辑
//方法一
System.out.println(e.getMessage());
//方法二
System.out.println(e.toString());
//方法三(最常用)
e.printStackTrace();
} finally {
//无论是否出现异常,都会执行
System.out.println("资源被释放了");
}
}
}
在异常类的超类 Throwable 类中,定义了三个异常处理的方法,使用时根据需要选择合适的即可。
String getMessage() 返回此 throwable 的简短描述。
String toString() 返回此 throwable 的详细消息字符串。
void printStackTrace() JVM打印异常对象,默认此方法,打印的异常信息是最全面的。
多个异常的处理
- 多个异常分别处理
每一个异常使用一对 try catch
- 多个异常一次捕获,多次处理
使用一个 try 多个 catch
- 多个异常一次捕获,一次处理
使用一个 try 一个 catch
注意事项
1.try 中是否产生异常
- 如果try中产生了异常,那么就会执行catch中的异常处理逻辑,执行完毕catch中的处理逻辑,继续执行try…catch之后的代码
- 如果try中没有产生异常,那么就不会执行catch中异常的处理逻辑,执行完try中的代码,继续执行try…catch之后的代码
2.finally不能单独使用,必须和try一起使用
3.finally一般用于资源释放(资源回收),无论程序是否出现异常,最后都要资源释放(IO)
4.如果try和finally同时存在 return 语句,那么try的返回值会被finally中的返回值替换掉
三、自定义的异常
Java 提供的异常类,不能够满足所有的实际需要,需要自己定义一些异常类。
格式
public class xxxException extends Exception | RuntimeException{
添加一个空参数的构造方法
添加一个带异常信息的构造方法
}
代码实例
定义 自定义异常类
public class DemoException extends Exception{
//添加一个空参数的构造方法
public DemoException(){
super();
}
/*
添加一个带异常信息的构造方法
查看源码发现,所有的异常类都会有一个带异常信息的构造方法,方法内部会调用父类带异常信息的构造方法,让父类来处理这个异常信息
*/
public DemoException(String massage){
super(massage);
}
}
使用 自定义异常类
public class DemoExceptionTest {
public static void main(String[] args) throws DemoException {
test01();
test02();
}
//使用 throws 关键字抛出异常
private static void test01() throws DemoException {
throw new DemoException("自定义异常");
}
//使用 try catch 捕获并抛出异常
private static void test02() {
try {
throw new DemoException("自定义异常");
} catch (DemoException e) {
e.printStackTrace();
}
}
}
注意事项
1.自定义异常类一般都是以Exception结尾,说明该类是一个异常类
2.自定义异常类,必须的继承Exception或者RuntimeException
继承 Exception类
:那么自定义的异常类就是一个编译期异常,如果方法内部抛出了编译期异常,就必须处理这个异常
,要么throws,要么try…catch…继承RuntimeException类
:那么自定义的异常类就是一个运行期异常,无需处理
,交给虚拟机处理(中断处理)