异常概念
异常机制的本质:就是当程序出现错误,程序安全退出的机制
Java是采用面向对象的方式来处理异常的。
处理过程:
1.抛出异常:在执行一个方法时,如果发生异常,则这个方法生成代表该异常的一个对象停止当前执行路径,并把异常对象交给JRE
2.捕获异常:JRE得到该异常后,寻找相应的代码来处理该异常。JRE在方法的调用栈中查找,从生成异常的方法开始回溯,直到找到相应的异常处理代码为止。
异常分类
JDK中定义了很多异常类,这些类对应了各种各样可能出现的异常情况,所有异常对象都是派生于Throwable类的一个实例。如果内置的异常类不能够,满足需要,还可以创建自己的异常类。
Java对异常进行分类,不同类型的异常分别不同的java类表示,所有异常的类java.lang.Throwable.Throwable下面又派生了两个子类:Error和Exception,Java异常类的层次结构
1.Error(错误):java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。比如:StackOverflowError[栈溢出]和OOM(out of memory),Error是严重错误,程序会崩溃
2.Exception:其他因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如空指针访问,试图读取不存在的文件,网络连接中断等等,Exception分为两大类:运行时异常和编译时异常。
运行时异常
派生于Runtime的异常,如被0除、数组下标越界、空指针等,其产生比较频繁,处理麻烦。如果显示的声明或铺获将对程序可读性和运行效率影响很大。因此由系统自动检测并将它们交给缺省的异常处理程序(用户不必对其处理)。
常见的运行时异常
- NullPointerException 空指针异常
- ArithmeticException 数学运算异常
- ArrayIndexOutOfBoundsException 数组下标越界异常
- ClassCastException 类型转换异常
- NumberFormatException 数字格式异常
编译时异常
所有不是RuntimeException的异常,统称为CheckedException,又称为“已检查异常”,如IOException、SQLException等以及用户自定义的EXception异常,这类异常在编译时就必须做出处理,否则无法通过编译。
异常的处理方法有:try/catch 捕获,使用throws 声明异常
Throws异常捕获
①如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。
②在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。
注意事项
①对于编译异常,程序中必须处理,必须try-catch或者throws
②对于运行时异常,程序中如果没有处理默认就是throws的方式处理
③子类重写父类的方法时,对抛出异常的规定:子类重写的方法,所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常的类型的子类型。
④在throws过程中,如果有方法try-catch,就可以不必throws.
try-catch捕获异常
捕获异常是通过3个关键字来实现的:try-catch-finally.用try来执行一段程序,如果出现异常,系统抛出一个异常,可以通过它的类型来捕捉(catch)来处理它,最后一步是通过finally语句为异常处理提供一个统一的出口,finally所指定的代码都要执行(catch语句可有多条,finally语句最多只能一条,根据自己的需要可有可无)。
因此try-catch有了执行的输出结果的顺序问题
①try-catch 没有异常的情况
public static void main(String[] args) {
try {
System.out.println("try代码块开始执行");
int i = 0;
System.out.println("try代码块结束");
}catch (Exception e){
System.out.println("执行catch代码块");
}
}
输出结果
try代码块开始执行
try代码块结束
说明:当代码没有发生异常时,则不会执行catch代码块。
②try-catch出现异常的情况
public static void main(String[] args) {
try {
System.out.println("try代码块开始执行");
int i = 1/0; //手动异常
System.out.println("try代码块结束");
}catch (Exception e){
System.out.println("执行catch代码块");
}
}
输出结果:
try代码块开始执行
执行catch代码块
说明:
当try代码块中有语句出现异常时则会运行catch代码块,try代码块中异常之后代码不执行。
③try-catch-finally 没有异常的情况
public static void main(String[] args) {
try {
System.out.println("try代码块开始执行");
int i = 1;
System.out.println("try代码块结束");
}catch (Exception e){
System.out.println("执行catch代码块");
}finally {
System.out.println("执行finally代码块");
}
}
输出结果:
try代码块开始执行
try代码块结束
执行finally代码块
说明
在没有异常的情况下,先执行try代码块的内容,再执行finally代码块的内容,不执行catch代码
④try-catch-finally出现异常的情况
public static void main(String[] args) {
try {
System.out.println("try代码块开始执行");
int i = 1/0;
System.out.println("try代码块结束");
}catch (Exception e){
System.out.println("执行catch代码块");
}finally {
System.out.println("执行finally代码块");
}
}
输出结果
try代码块开始执行
执行catch代码块
执行finally代码块
说明:
首先执行try代码块,当出现异常时,执行catch代码块,不再执行异常之后的try代码块中的内容,最终执行finally代码块。
⑤try-catch-finally 没有异常,有返回值
public static int tryMethod(){
try{
System.out.println("try执行开始");
System.out.println("try执行结束");
return 1;
}catch (Exception e) {
System.out.println("执行catch");
return 2;
}finally {
System.out.println("执行finally");
return 3;
}
}
代码结果:
try执行开始
try执行结束
执行finally
3
说明:在没有异常情况下,finally的代码块执行在try代码块return语句之前执行。若finally没有return语句时,才执行try代码块中的return语句。
⑥try-catch-finally 有异常,有返回值
public static int tryMethod(){
try{
System.out.println("try执行开始");
int i = 1/0;
System.out.println("try执行结束");
return 1;
}catch (Exception e) {
System.out.println("执行catch");
return 2;
}finally {
System.out.println("执行finally");
return 3;
}
}
输出结果:
try执行开始
执行catch
执行finally
3
说明:在发生异常的时候,同样的catch代码块中return语句执行之前,先执行finnally代码块,若finnally返回值,先执行finnally代码块中return语句,否则才执行catch中的return语句。
注意事项
- 如果异常发生了,则异常发生后面的代码不会执行,直接进入到catch代码块
- 如果异常没有发生,则顺序执行try的代码块,不会进入到catch
- 如果希望不管是否发生异常,都执行某代码块(比如:关闭连接,释放资源等)则使用finally关键字进行处理
- 可以有个多个catch语句,铺获不同的异常(进行不同的业务处理),要求父类异常在后,子类异常在前,如果发生异常,只会匹配一个catch。
- 可以进行try-finally配合使用,这种用法相当于没有铺获异常,因此程序会直接崩溃掉,应用场景,就是执行一个代码,不管是否发现异常,都必须执行某个业务逻辑。
自定义异常
当程序中出现了某些“错误”,但该错误信息并没有在Throwable子类中描述,这个时候可以自己设计异常类,用于描述该错误信息。
自定义异常的步骤
①定义类:自定义异常类继承Exception或RuntimeException
②如果继承Exception属于编译异常
③如果继承RuntimeException,属于运行异常(一般来说,继承RuntimeException)
throw 和throws的区别
意义 | 位置 | 后面跟的东西 | |
throws | 异常处理的一种方式 | 方法声明处 | 异常类型 |
throw | 手动生成异常对象的关键字 | 方法体中 | 异常对象 |