详解Java异常

详解Java异常

异常的定义:

异常指不期而至的各种状况,如:文件找不到、网络连接失败、非法参数等。异常是一个事件,它发生在程序运行期间,干扰了正常的指令流程。Java通过API中Throwable类的众多子类描述各种不同的异常。因而,Java异常都是对象,是Throwable子类的实例,描述了出现在一段编码中的错误条件。当条件生成时,错误将引发异常。

看一段简单的代码:

public static void main(String[] args) {

        // TODO Auto-generated method stub

        System.out.println("异常测试开始");

        System.out.println(1/0);

        System.out.println("异常测试结束");

    }

运行后,输出如下所示:

Exception in thread "main" 异常测试开始

java.lang.ArithmeticException: / by zero

    at Demo.main(Demo.java:12)

显然这段代码出现了:除数为0的异常。出现异常后,它后面的语句 System.out.println("异常测试结束");没有被执行,可见异常的出现干扰了正常的指令流程。

除数为0这种异常属于java中的ArithmeticException,Java异常类层次结构图如下所示:

Java异常类层次结构图

如上图所示,Throwable: 有两个重要的子类:Exception(异常)和 Error(错误),二者都是 Java 异常处理的重要子类,各自都包含大量子类。

Error(错误):

是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时JVM(Java 虚拟机)出现的问题。例如,Java虚拟机运行错误(Virtual MachineError),当 JVM不再有继续执行操作所需的内存资源时,将出现OutOfMemoryError。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。这些错误表示故障发生于虚拟机自身、或者发生在虚拟机试图执行应用时,如Java虚拟机运行错误(VirtualMachineError)、类定义错误(NoClassDefFoundError)等。这些错误是不可查的,因为它们在应用程序的控制和处理能力之外,而且绝大多数是程序运行时不允许出现的状况。对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。在Java中,错误通过Error的子类描述。

Exception(异常):

是程序本身可以处理的异常。Exception类有一个重要的子类 RuntimeException。RuntimeException 类及其子类表示"JVM常用操作"引发的错误。例如,若试图使用空值对象引用、除数为零或数组越界,则分别引发运行时异常(NullPointerException、ArithmeticException)和ArrayIndexOutOfBoundException。

异常的对象来源:

有两个来源,一是Java运行时环境自动抛出系统生成的异常,而不管你是否愿意捕获和处理,它总要被抛出!比如除数为0的异常。二是程序员自己抛出的异常,这个异常可以是程序员自己定义的,也可以是Java语言中定义的,用throw关键字抛出异常,这种异常常用来向调用者汇报异常的一些信息。

异常的分类:

通常,Java的异常(包括Exception和Error)分为可查的异常(checked exceptions)和不可查的异常(unchecked exceptions)。

可查异常(编译器要求必须处置的异常):

正确的程序在运行中,很容易出现的、情理可容的异常状况。可查异常虽然是异常状况,但在一定程度上它的发生是可以预计的,而且一旦发生这种异常状况,就必须采取某种方式进行处理。除了RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。

不可查异常(编译器不要求强制处置的异常):

包括运行时异常(RuntimeException与其子类)和错误(Error)。

运行时异常:都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。

错误(Error)描述了Java运行时系统的内部错误和资源耗尽错误。应用程序不应该抛出这种异常错误!

异常关键字:

Java异常处理通过5个关键字try、catch、throw、throws、finally进行管理。基本过程是用try语句块包住要监视的语句,如果在try语句块内出现异常,则异常会被抛出,你的代码在catch语句块中可以捕获到这个异常并做处理;还有以部分系统生成的异常在Java运行时自动抛出。你也可以通过throws关键字在方法上声明该方法要抛出异常,然后在方法内部通过throw抛出异常对象。finally语句块会在方法执行return之前执行,一般结构如下:

try{

程序代码

 }catch(异常类型1 异常的变量名1){

程序代码

 }catch(异常类型2 异常的变量名2){

程序代码

}finally{

程序代码

 }

try...catch

典型的异常代码示例如下所示:

public static void main(String[] args) {

        // TODO Auto-generated method stub

        System.out.println("异常测试开始");

        try{

            System.out.println(1/0);

        }catch(ArithmeticException e){

            System.out.println("捕获算数异常");

            e.printStackTrace();

        }

        System.out.println("异常测试结束");

    }

运行结果如下:

异常测试开始

捕获算数异常

异常测试结束

java.lang.ArithmeticException: / by zero

    at Demo.main(Demo.java:10)

由此可见,当异常发生时,异常处理机制成功捕获到了异常(执行catch中的代码),保障了程序的继续运行(代码System.out.println("异常测试结束");成功执行。)

更改上面的代码中的异常类型为NullPointerException,代码如下所示:

    System.out.println("异常测试开始");

        try{

            System.out.println(1/0);

        }catch(NullPointerException e){

            System.out.println("捕获算数异常");

            e.printStackTrace();

        }

        System.out.println("异常测试结束");

运行结果如下:

异常测试开始

Exception in thread "main" java.lang.ArithmeticException: / by zero

    at Demo.main(Demo.java:11)

由此可见,当使用错误的异常类型进行异常处理时,是无法捕获异常的!所以当你不知道具体的异常类型时可以使用类Exception,它是各种异常的父类,更改上面的代码中异常类型为Exception,代码如下所示:

      System.out.println("异常测试开始");

        try{

            System.out.println(1/0);

        }catch(Exception e){

            System.out.println("捕获算数异常");

            e.printStackTrace();

        }

        System.out.println("异常测试结束");

运行结果如下:

异常测试开始

捕获算数异常

异常测试结束

java.lang.ArithmeticException: / by zero

    at Demo.main(Demo.java:11)

由此可见,使用Exception可以成功处理该异常。这种方式的优点是可以轻松的处理各种异常,但缺点是不能针对不同种类的异常进行不同的编码处理。

finally

关于finally{}的含义就是:无论代码有无异常发生,都会执行finally中的代码,这里就不多做解释了。

关于throw和throws 的解释如下:

throws

throws语句用在方法声明后面, 表示方法中可能存在的Exception 将抛出异常给调用此方法的方法,当前方法不做异常的处理,但是调用该方法时必须进行异常处理,否则ide会提示错误,如下图所示:

throw

throw语句用在方法体内,表示抛出异常程序在执行到throw语句时立即停止,它后面的语句都不被执行。

代码如下所示:

public static void expfun2(int a,int b) {  

        System.out.println("异常测试开始");

        if (b==0)

{

     throw new ArithmeticException();   

}

        System.out.println(a/b);   

        System.out.println("异常测试结束");

    }

调用方法expfun2(8,0);运行结果如下:

异常测试开始

Exception in thread "main" java.lang.ArithmeticException

    at Demo.expfun2(Demo.java:28)

    at Demo.main(Demo.java:10)

throw和throws区别如下:

1. throw是抛出了异常,执行throw则一定抛出了某种异常;throws表示出现异常的一种可能性,并不一定会发生这些异常。

2、throw用在方法实现中;而throws用在方法声明中。

3、throw只能用于抛出一种异常;而throws可以抛出多个异常

自定义异常

如果Java自带的异常不能满足我们业务的需求, 这个时候我们可以自定义异常来进行对业务异常的处理。最简单的实现自定义异常的方法就是创建一个类,继承其中想要自定义的异常类,重写他的构造方法。

自定义异常代码实现如下:

public classMyExceptionextends Exception {

    public MyException()

   {

    }

    publicMyException(String str) {

        super(str);

    }

}

使用自定义异常代码如下:

public static void expfun8(int a, int b) throws MyException{

        System.out.println("异常测试开始");

        if (b== 0) {

            throw new MyException("自定义异常!");

        }

        System.out.println(a/ b);

        System.out.println("异常测试结束");

    }

你可能感兴趣的:(详解Java异常)