Java 异常处理机制

来源:互联网 发布:ant编译java 编辑:程序博客网 时间:2024/06/05 15:09

异常的引入

程序在编译通过后代表程序没有语法错误,但是并不能说明程序的健壮性好,不能说明程序运行中不会出现错误,而很多时候程序的语法正确只是基本要求,而程序的健壮性才是程序性能的一个重要衡量标准。看下面除法计算的程序:

//简单除法计算程序class myMath {    public static int div (int x,int y)  {        return x / y ;    }}public class Demo {    public static void main(String args[]) {        int x = String.parseInt(args[0]) ;        int y = String.parseInt(args[1]) ;        System.out.println(myMath.div(x,y)) ;        System.out.println("*******************") ;    }}

这是简单的除法计算,运行时计算输入的两参数的商,程序运行过程中可能会出现如下问题:

执行时无输入参数(java TestDemo),ArrayIndexOutOfBoundsException
输入的参数不是数字(java TestDemo a b),NumberFormatException
输入的被除数为0(java TestDemo 10 0),ArithmeticException

此时有可能产生多种异常情况使得程序中止进行,而在Java程序中提供多catch语句来捕获不同类型的异常,此时所有异常都是经过大量分析后已知的异常,其实此时的异常处理以使用if else 语句来代替。

//使用try catch语句进行异常的捕获及处理class myMath {    public static int div (int x,int y)  {        return x / y ;    }}public class Demo {    public static void main(String args[]) {        int x = Integer.parseInt(args[0]) ;        int y = Integer.parseInt(args[1]) ;        try{            System.out.println(myMath.div(x,y)) ;        }catch(ArrayIndexOutOfBoundsException e){            System.out.println("我是来处理数组越界异常的!") ;        }catch(NumberFormatException e){            System.out.println("我是来处理参数格式异常的!") ;        }catch(ArithmeticException e){            System.out.println("我是来处理数学计算异常的!") ;        }        System.out.println("*******************") ;    }}

异常处理流程

Java之中之所以会使用异常处理机制,主要的目的就是可以减少用户的 if else判断,只是一种严格的方案。下面针对异常做一个流程的说明。

异常的处理流程

程序遇到异常的处理流程如下:
1、当程序运行过程中产生异常之后,会由JVM根据产生的异常类型自动实例化一个与之相匹配的实例化异常对象。(对象可以进行引用传递,包含很多信息)
2、此时JVM会判断在出现异常的代码中是否存在try语句进行异常捕获。
3、如果没有try语句,则交给JVM默认的处理方式。
4、如果存在try语句,则会由try捕获异常类的实例化对象,而又与try语句之后的每个catch语句进行匹配,如果当前catch不匹配,则会交由后面的catch继续匹配(catch语句顺序问题,范围小的异常放在前面)。
5、如果有匹配成功catch语句,则使用该语句进行异常处理,如果始终没有匹配的catch语句,则交由JVM进行默认处理(前提查看是否存在finally语句)。
6、如果程序中存在finally语句,在所有catch无法进行异常处理时,会判断是否有finally语句,如果有,执行finally语句之后,交由JVM做默认处理,所有catch执行完毕之后也要判断是否存在有finally。
7、进入到finally代码中有两种情况,一种是没有处理异常,则执行完finally代码之后,程序不再执行,交由JVM默认处理;一种是异常处理完毕,如果处理完毕则往下执行其他代码。

异常的继承关系

先看一下异常类的继承关系,以ArithmeticException和NumberFormatException为例。
异常类的继承关系

可以看到所有的异常都继承了Throwable类和Exception类,而Throwable类指的就是抛出信息类,这个类下面直接子类有两个:Exception类和Error类。

问:Error 和 Exception的区别?
1. Error:表示的是JVM系统出错,此时程序没有执行,所以用户不能处理。
2. Exception:表示的是所有程序运行过程中出现的异常,用户可以进行处理。

一般而言,由于Throwable表示的范围太大了,程序之中处理的往往不会是Throwable,而都是Exception,按照之前向上转型的概念来讲,所有子类对象都可以自动完成向上转型,使用父类接收,那么能表示出来的所有异常都是Exception的子类,所有的异常类对象都可以自动转换为Exception类对象。例如:

//程序使用Exception类接收所有异常,通过printStackTrace()方法打印异常信息class myMath {    public static int div (int x,int y) {        return x / y ;    }}public class Demo {    public static void main(String args[]) {        try {            System.out.println(myMath.div(10,0)) ;        }catch(Exception e) {        //异常类中都有方法printStackTrace(); 方法,可以通过异常类的实例化对象调用此方法,来打印异常信息。            e.printStackTrace() ;        }        System.out.println("*******************") ;    }}

异常类中都有方法printStackTrace(); 方法,可以通过异常类的实例化对象调用此方法,来打印异常信息。

Throws关键字

在类之中所有的操作都是以方法体现,如果某些方法出现异常,希望在被调用处进行处理的话,就使用throws进行声明。也就是说方法可以通过Throws关键字指出可能出现的异常,然后用户在调用该方法的时候通过try catch语句对异常进行处理。

//在方法定义上使用throwsclass myMath {    public static int div (int x,int y) throws Exception {        return x / y ;    }}public class Demo {    public static void main(String args[]) {        try {            System.out.println(myMath.div(10,0)) ;        }catch(Exception e) {            e.printStackTrace() ;        }        System.out.println("*******************") ;    }}

日后会用大大量的Java类库进行项目开发,那么对于不熟悉的类库,在这些类方法的设计师考虑到可能会出现的异常,一般会在方法上使用throws抛出异常,那么用户根据这些抛出就可以使用try catch进行处理。

同时需要注意的是,既然在方法上可以使用throws,那么主方法main也可以使用throws,表示主方法不处理异常,交给JVM进行处理。一般这样的方法很少出现,因为在调用处一定要进行异常处理,否则只能交由JVM。

//异常通过main主函数抛出,交由JVM进行处理,在方法调用出不再使用try catch进行处理class myMath {    public static int div (int x,int y) throws Exception {        return x / y ;    }}public class Demo {    public static void main(String args[]) throws Exception{            System.out.println(myMath.div(10,0)) ;            System.out.println("*******************") ;    }}

Throw关键字

如果在异常处理之中,使用了throw,那么表示人为抛出一个异常,而throw一般都在方法中使用。

public class Demo {    public static void main(String args[]){     try{             throw new Exception("我是人为抛出的异常!") ;        } catch(Exception e) {        e.printStackTrace() ;        }       System.out.println("*************") ;

问:请解释throw和throws的区别?
1.Throw主要用于方法之中,表示人为抛出一个异常类的实例化对象。
2.Throws 在方法的声明处使用,表示此方法不处理异常,所有的异常交给被调用处进行处理。

finally关键字

在try catch语句后面添加finally语句,表示异常是否处理都执行finally里面的代码。但是实际情况远非如此,finally里面的代码块并不一定都会执行。参考文章:Java 中 finally 语句块的深度辨析

代码模型:异常处理结构(核心)

提出个问题:目前为止,finally无用、throw无用,为了解释这两个操作的含义,给出一个异常处理的标准结构。

示例:定义一个div()方法(定义在MyMath类里面),
这个方法要求如下:
1.此方法中所有出现的异常一定交给被调用处进行处理;
2.在进行处罚计算开始首先要输出一行提示信息:“1、除法计算开始,打开计算功能”;
3.在除法计算完毕输出“2、除法计算结束,关闭计算功能”;

class myMath {    public static int div (int x,int y) throws Exception {        int result = 0 ;        System.out.println("1.除法开始,打开计算器") ;        try{            result = x / y ;        }catch(Exception e) {            throw e ;        }finally{            System.out.println("2.除法结束,关闭计算器") ;        }        return result ;    }}public class Demo {    public static void main(String args[]) throws Exception{        int x = Integer.parseInt(args[0]) ;        int y = Integer.parseInt(args[1]) ;        try {            System.out.println("计算结果:" + myMath.div(x,y)) ;        }catch(Exception e) {            e.printStackTrace() ;        }    }}

在本结构中出现了try,catch,finally,throw,throws的标准组合应用,日后可以把两条输出语句作为资源的打开和关闭。例如文件打开、关闭,网络的链接、断开。

RuntimeException类

问:Exception和RunTimeException的区别?列举几个常见的RunTimeException子类?
1.用户可以处理的异常都需要继承Exception类,而RuntimeException是Exception的子类;
2.Exception的异常要求用户强制性进行处理,而RunTimeException异常用户可以选择性进行处理,如果代码之中没有处理,则出现异常会交由JVM进行默认处理。
3.常见的RunTimeException子类:ArithmeticException, ClassCastException, NullPointerException, IndexOutOfBoundsException

原创粉丝点击