文章目录
0. 概述
-
异常:在Java中,异常是指程序运行时,不期望发生的事情,使程序不按照程序员的预期运行,即编译时或者运行时出现的错误
故异常分为编译时异常与运行时异常
在Java中默认当异常发生时程序退出,终止.为了不出现这种情况,Java提供了异常处理机制
-
异常与错误的区别:错误是指程序员写代码时的语法错误,是我们编写代码时要避免的
而异常是指程序本身可以处理的问题,即我们使用了异常处理之后,程序遇到异常不会退出终止,而是在处理了异常之后继续运行
-
异常分类:
java中的程序错误(Error)和异常(Exception)都继承了Throwable类,如图所示:
**运行时异常:**
包括RuntimeException及其子类,运行时异常在编译阶段不会报错。可以选择处理也可以选择不处理(运行时异常发生概率较小),不处理程序也可以通过编译 (如空指针异常 : NullPointerException,数组索引越界异常: ArrayIndexOutOfBoundsException,类型转换异常:ClassCastException,数学操作异常:ArithmeticException,数字转换异常: NumberFormatException)
出现运行时异常一般是程序员业务没有考虑好或者是编程逻辑不严谨引起的程序错误,
大概率是自己的水平有问题!
**编译时异常:**
所有编译时异常都是Exception的直接子类,在编写程序时必须对这类异常进行处理,不然程序编译不通过.(如FileNotFoundException,ClassNotFoundException,SQLException,NoSuchFieldException,NoSuchMethodException,日期解析异常:ParseException)
出现编译时异常主要是提醒程序员注意,将异常处理了就行了
-
异常处理的目的:
避免异常的出现,同时处理可能出现的异常,让代码更稳健。
1. 异常处理
1.1 异常的默认处理
- 默认会在出现异常的代码那里自动的创建一个异常对象:ArithmeticException
- 异常会从方法中出现的点这里抛出给调用者,调用者最终抛出给JVM虚拟机
- 虚拟机接收到异常对象后,虚拟机处理不了异常,所以先在控制台直接输出异常栈信息数据
- 然后直接从当前执行的异常点干掉当前程序。
后续代码没有机会执行了,因为程序已经死亡
1.2 异常处理机制
出现异常后有三种方式处理异常:
- 出现异常直接抛出去给调用者,调用者也继续抛出去(使用throws关键字)
- 出现异常自己捕获处理,不麻烦别人。(使用try-catch机制,这种方式调用者并不知道出异常了)
- 前两者结合,最好的方式,将异常一直抛出去直到给调用者,让调用者知道出异常了,调用者自己处理异常
1.3 捕获异常和抛异常的注意点
在Java推荐的语法中,如果我们在发现异常后不对异常做特殊操作,只是将异常信息打印在控制台或日志中,那不论是抛异常还是捕获异常都推荐只写throws Exception
和catch(Exception e)
,简化书写.
1.4 finally子句
在try-catch语句块中还可以加上finally子句
finally子句常用来释放资源,且使用finally子句之后,无论是否发生异常,finally子句中的内容都会被执行
即使在try语句块中return,也会继续执行完finally中的语句再return,并且finally中的return会覆盖try或者catch中的return
即finally模块一定会被运行!(能使finally子句失效的方法是System.exit(0);
)
并且try不能单独使用,只能以try-catch-finally,try-catch,try-finally这三种形式被使用
在java的语法建议中,当finally语句被执行后,整个方法必须结束(会先运行完finally中的语句再return),但不建议在finally中return,因为finally中的return会覆盖前面的return
1.5 throws与throw
- throws在方法声明的位置上使用,表示上报异常给调用者,表示此方法在调用时必须处理异常
- throw在方法体中使用,表示手动抛出方法中的异常,这个异常对象可能是自己实例化或者抛出已存在的
1.6 try-catch-finally总结
- catch 不能独立于 try 单独存在
- catch语句块中不能没有内容
- 在 try/catch 后面添加 finally 块并非强制性要求的
- try 语句块后不能既没 catch 块也没 finally 块
- try里面越少越好
- try, catch, finally 块之间不能添加任何代码。
- finally里面的代码最终一定会执行(除了JVM退出)
- 如果程序可能存在多个异常,需要多个catch进行捕获。
异常如果是同级关系,catch谁前谁后没有关系
如果异常之间存在上下级关系,上级需要放在后面
2. 自定义异常
讲解自定义异常之前先了解一下Throwable 类的主要方法:
方法 | 说明 |
---|---|
public String getMessage() | 返回异常的详细信息字符串 |
public void printStackTrace() | 打印异常栈信息,即错误输出流。 |
自定义异常的作用:在业务开发中提醒程序员更加强烈注意,一定需要处理
自定义的异常应该总是包含如下的构造函数(但通常提供无参和带有String参数的也够了):
- 一个无参构造函数
- 一个带有String参数的构造函数,并传递给父类的构造函数。
- 一个带有String参数和Throwable参数,并都传递给父类构造函数
- 一个带有Throwable 参数的构造函数,并传递给父类的构造函数。
下面提供IOException类的完整源代码,在我们自定义异常时可以借鉴IOException的定义方式:
package java.io;
public class IOException extends Exception {
static final long serialVersionUID = 7818375828146090155L;
public IOException() {
super();
}
public IOException(String message) {
super(message);
}
public IOException(String message, Throwable cause) {
super(message, cause);
}
public IOException(Throwable cause) {
super(cause);
}
}
自定义异常使用步骤:
在我们自定义异常之后,应该在可能发生异常的方法体中throw new 自定义异常(“错误信息”),再使用throws关键字将异常抛给调用者让调用者解决