一、认识异常
在Java中所有的异常(Exception)和错误(Error)都继承了同一个父类Throwable,他们的关系如下:
1.1 Error(错误):
是指程序无法处理的错误,表示运行应用程序时比较严重的问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时JVM(Java 虚拟机)出现的问题。
1.2 异常(Exception):
是指在程序执行时由于程序处理逻辑上的错误而导致程序中断的一种指令流。通俗的说,就是程序员写的代码错误。
两者的区别:错误无法处理,异常可以被程序本身处理。
二、异常的分类
![](https://i-blog.csdnimg.cn/blog_migrate/25cd93c469a891b5bb74be1c1337fc00.png)
1、Exception分为两大类:
运行时异常:即程序运行时发生的异常,编译器不强制要求处理的异常。一般是指编译时的逻辑错误,是程序员应该避免出现的异常。java.lang.RuntimeException类及它的子类都是运行时异常。对于运行时异常,可以不作处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响。
编译时异常:即编程时编译器检查出的异常,是编译器要求必须处置的异常。
2、可以统一使用Exception处理来简化异常处理。
3、处理多个异常时,捕获范围小的异常要放在捕获异常范围大的异常之前处理。
4、常见的运行时异常:
5、常见的编译异常:
三、异常的处理
异常处理的方式有两种:
1、try-catch-finally:程序员在代码中捕获发生的异常,然后进行处理。
在Java中,对异常处理有三个核心关键字:try、catch、finally。常用格式如下:
try {
//有可能出现异常的语句
} catch (异常类型 对象) {
//异常处理 ;
} catch (异常类型 对象) {
//异常处理 ;
} finally {
//不管有没有出现异常,这里的代码都会执行
}
我们在try语句中捕获可能出现异常的代码。如果出现异常,则跳转到catch语句中找到对应的异常类型进行处理。最后不管有没有异常,都会执行finally中的语句块。注意:finally语句块是可以省略的。如果省略,则在执行完catch语句块之后,程序继续执行后边的代码。
public class Test {
public static void main(String[] args) {
try {
int a = 10 / 0;
System.out.println(a);
} catch (ArithmeticException e) {
System.out.println("处理异常:");
e.printStackTrace();
}finally {
System.out.println("不管有没有异常,我都会执行!");
}
}
}
执行结果:
处理异常:
不管有没有异常,我都会执行!
java.lang.ArithmeticException: / by zero
at com.zxl.Demo.Test.main(Test.java:10)
为了能够进行异常的处理,可以使用异常类提供的printStackTrace()方法输出完整的异常信息。
2、throws异常处理:将发生的异常抛出,交给调用者(方法)来处理,最顶级的处理者就是JVM。
1)如果一个方法(中的语句执行时)可能产生某种异常,但是并不确定如何处理这种异常,则此方法应显式地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。
2)在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。
3、对于编译异常,程序中必须处理,比如try-catch或者throws;
4、对于运行时异常,程序中如果没有处理,默认就是throws的方式处理;
5、子类重写父类的方法时,对抛出异常的规定:子类重写的方法,所抛出的异常类型要么和父类抛出的异常一致, 要么为父类抛出的异常的类型的子类型
6、在throws过程中,如果有方法try-catch,就相当于处理异常,就可以不必throws。
四、异常处理流程
(1)Java中可以处理的异常都是在运行时产生的,当程序运行到产生异常的代码时,会由JVM帮助用户去判断此异常的类型,并自动进行指定类型的异常类对象实例化处理;
(2)如果此时程序中并没有提供异常处理,则会采用JVM默认的异常处理方式进行处理,首先进行异常信息的打印,然后直接退出当前程序;
(3)如果此时程序中存在异常处理,那么这个异常类的实例化对象会被try语句所捕获;
(4)try捕获到异常后将会与和它匹配的catch中的异常类型依次进行比对,如果相同则进行处理;如果不匹配,则继续匹配后续的catch类型;如果都不匹配,那么表示该异常无法处理;
(5)不管异常是否进行处理,最终都会执行finally语句,执行完finally语句后,程序会进一步判断当前的异常是否已经处理,如果处理了,则继续执行后续的代码;如果没有,则交给JVM进行默认处理。
五、throw关键字
在默认情况下,所有的异常类的实例化对象都会由JVM默认实例化并且自动抛出。为了方便用户手动进行异常的抛出,JVM提供了throw关键字。
public static void main(String[] args) {
try { //异常对象不再由系统生成的,手动实例化
throw new Exception("自己手动抛出的对象...");
} catch (Exception e) {
e.printStackTrace();
}
}
执行结果:
java.lang.Exception: 自己手动抛出的对象...
at com.zxl.Demo.Test.main(Test.java:10)
六、throws和throw的区别
意义 | 位置 | 后面跟的 | |
throws | 异常处理的一种方式 | 方法声明处 | 异常类型 |
throw | 手动生成异常对象的关键字 | 方法体中 | 异常对象 |
七、自定义异常
1、当程序中出现了某些“错误”,但该错误信息并没有在Throwable子类中描述处理,此时可以自己设计异常类,用于描述该错误信息。
2、自定义异常类继承自Exception(编译异常)或RuntimeException(运行异常);
3、一般情况下,我们自定义异常是继承 RuntimeException,把自定义异常做成运行时异常,这样做的好处是,我们可以使用默认的处理机制,比较方便。