Java之异常处理
当程序运行出现意外情况时,系统会自动生成一个Exception对象来通知程序。从而实现"业务功能实现代码"和"错
误处理代码"分离,提供更好的可读性。
try{
// 业务功能实现代码
}catch(ExcetionCslass1 e1){
// 错误处理代码
}catch(ExcetionCslass2 e2){
// 错误处理代码
}
...
异常处理流程
当Java运行时环境接收到异常对象后,会依然判断该异常对象是否是catch块后异常类或子类的实例,如果是,
Java运行时环境将调用该catch块来处理该异常;否则再次拿该异常对象和下一个catch块里的异常类进行比较。
正常情况下,如果try块被执行一次,则try块后只有一个catch块会被执行,绝不可能有多个catch块被执行。
除非在循环中使用continue开始下一次循环,下一次循环又重新运行try块,这才可能导致多个catch块被执行。
异常和错误
错误:一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,动态链接失败等,这种错误无法恢复,不可
被catch捕获,将导致应用程序中断。
一个catch可以捕获多个异常
捕获多种类型异常时,异常变量有隐式final修饰,因此程序不能对异常变量重新赋值。
try{
...
}catch(IndexOutOfBoundsException|NumberFormatException|ArithmeticException ie){
ie = new ArithmeticException("test"); // error!
}catch(Exception e){
e = new RuntimeException("test"); // 捕获单个异常,异常变量没有final修饰,这个代码没问题
}
...
使用finally回收资源
为了保证一定能回收try块中打开的物理资源,异常处理机制提供了finally块,不管try块中的代码是否出现异
常,也不管哪一个catch块被执行,甚至在try块或catch块中执行了return语句,finally块总会被执行。
try{
// 业务功能实现代码
}catch(ExcetionCslass1 e1){
// 错误处理代码
}catch(ExcetionCslass2 e2){
// 错误处理代码
}finally{
// 资源回收
}
...
当执行try块,catch块时遇到了return或throw语句,这两个语句都会导致该方法立即结束,但是系统执行这两
个语句并不会结束该方法,而是去寻找该异常处理流程中是否包含finally块。
如果没有finally块,程序立即执行return或throw语句,方法终止;
如果有finally块,系统立即开始执行finally块
只有当finally块执行完成后,系统才会再次调回来执行try块,catch块里的return或thorw语句;
如果finally块里也使用了return或throw等导致方法终止的语句,finally块已经终止了方法,系统将不会跳回去
执行try块,catch块里的任何代码。
自动关闭资源的try语句
Java7增强了try语句的功能---它允许在try关键字后紧跟一对圆括号,圆括号可以声明,初始化一个或多个资源
try语句在该语句结束时自动关闭资源。
为了保证try语句可以正常关闭资源,这些资源实现类必须实现AutoCloseable或Closeable接口,实现这2个接
口就必须实现close方法。
try(BufferedReader br = new BufferedReader(new FileReader("test")){
// 使用资源
...
}// try语句在该语句结束时自动关闭资源
异常体系
Checked异常和Runtime异常
异常被分为两类:Checked异常和Runtime异常。所有的RuntimeException类及其子类的实例被称为Runtime
异常;不是RuntimeException类及其子类的异常实例则被称为Checked异常。
对于Checked异常处理方式有两种:
1.当前方法明确知道如何处理该异常,程序应该使用try...catch块捕获该异常,然后在对应的catch块中修复
该异常。
2.当前方法不知道如何处理这种异常,应该在定义该方法时抛出异常
抛出异常
当前方法不知道如何处理这种异常,该异常应该由上一级调用者处理。如果main方法抛出异常则交给JVM处理。
JVM处理该异常:打印异常信息,终止程序。
public class Test{
public static void main(String[] args)throws IOException{
try{
}
catch{ // catch可以和whrow同时使用
}
}
}
抛出异常的规则:子类方法声明的抛出异常类型应是父类方法声明抛出的异常类型的子类或相同。
子类方法声明抛出的异常不允许比父类方法声明抛出的异常多。
自定义异常类
自定义异常都应该继承Exception基类,如果系统自定义Runtime异常,则应该继承RuntimeException基类。
定义异常类时通常需要提供两个构造器:
1.无参数构造器。
2.带一个字符串构造器,这个字符串将作为该异常对象的描述信息。
public class AuctionException extends Exception{
public AuctionException(){}
public AuctionException(String msg){
}
}
异常跟踪栈
面向对象的应用程序运行时,经常会发生一系列方法调用,从而形成"方法调用栈",异常的传播则相反:
只要异常没有被完全捕获(包括异常没有被捕获,或异常被处理后重新抛出了新异常),异常从发生异常的
方法逐渐向外传播,首先传给该方法的调用者,该方法调用者再次传给其调用者。。。直到最后传到main方法,
如果main方法依然没有处理该异常,JVM会终止该程序,并打印异常的跟踪信息。
异常处理规则
1.使程序代码混乱最小化
2.捕获并保留诊断信息
3.通知合适人员
4.采用适合的方式结束异常活动