JAVA 的异常那些事

异常的概念

异常指不期而至的各类情况,如:文件找不到、网络链接失败、非法参数等。异常是一个事件,它发生在程序编译或运行期间,干扰了正常的指令流程。java

Java中的Throwable类是全部异常的基类。它的的众多子类描述各类不一样的异常。于是,Java异常都是对象,是Throwable子类的实例,描述了出如今一段编码中的 错误条件。当条件生成时,错误将引起异常。面试

Java异常类层次结构及概念

Throwable

    Throwable 类是 Java 语言中全部错误或异常的超类编程

异常与错误

    注意:异常和错误的区别:异常能被程序自己能够处理,错误是没法处理。数组

    1 Exception 类及其子类用来处理程序错误,它指出了合理的应用程序想要捕获的条件,表示程序自己能够处理的异常网络

    2 Error 是及其子类用来处理系统错误,表示仅靠程序自己没法恢复的严重错误,用于指示合理的应用程序不该该试图捕获的严重问题,Java编译器不去检查这类异常框架

运行时异常

    RuntimeException 类及其子类表示“JVM 经常使用操做”引起的错误。例如,若试图使用空值对象引用、除数为零或数组越界,则分别引起运行时异常(NullPointerException、ArithmeticException)和 ArrayIndexOutOfBoundException。编程语言

可查异常 和 不可查异常  

    一般,Java的异常(包括Exception和Error)分为可查的异常(checked exceptions)和不可查的异常(unchecked exceptions)
      函数

    可查异常(编译器要求必须处置的异常):正确的程序在运行中,很容易出现的、情理可容的异常情况。可查异常虽然是异常情况,但在必定程度上它的发生是能够预计的,并且一旦发生这种异常情况,就必须采起某种方式进行处理。性能

      除了RuntimeException及其子类之外,其余的Exception类及其子类都属于可查异常。这种异常的特色是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,不然编译不会经过。编码

     不可查异常(编译器不要求强制处置的异常):包括运行时异常(RuntimeException与其子类)和错误(Error)。

     Exception 这种异常分两大类运行时异常和非运行时异常(编译异常)。程序中应当尽量去处理这些异常。

运行时异常 和非运行时异常

       运行时异常:都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是不检查异常,程序中能够选择捕获处理,也能够不处理。这些异常通常是由程序逻辑错误引发的,程序应该从逻辑角度尽量避免这类异常的发生。

      运行时异常的特色是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即便没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译经过。
       非运行时异常 (编译异常):是RuntimeException之外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,若是不处理,程序就不能编译经过。如IOException、SQLException等以及用户自定义的Exception异常,通常状况下不自定义检查异常。

处理异常机制

    在 Java 应用程序中,异常处理机制为:抛出异常,捕捉异常。异常老是先被抛出,后被捕捉的。

        对于运行时异常、错误或可查异常,Java技术所要求的异常处理方式有所不一样。

        只有在try里面是有System.exit(0)来退出JVM的状况下finally块中的代码才不会执行。

        因为运行时异常的不可查性,为了更合理、更容易地实现应用程序,Java规定,运行时异常将由Java运行时系统自动抛出,容许应用程序忽略运行时异常。

       对于方法运行中可能出现的Error,当运行方法不欲捕捉时,Java容许该方法不作任何抛出声明。由于,大多数Error异常属于永远不能被容许发生的情况,也属于合理的应用程序不应捕捉的异常。

       对于全部的可查异常,Java规定:一个方法必须捕捉,或者声明抛出方法以外。也就是说,当一个方法选择不捕捉可查异常时,它必须声明将抛出异常。

 Throws抛出异常的规则:

    1) 若是是不可查异常(unchecked exception),即Error、RuntimeException或它们的子类,那么能够不使用throws关键字来声明要抛出的异常,编译仍能顺利经过,但在运行时会被系统抛出。

    2)必须声明方法可抛出的任何可查异常(checked exception)。即若是一个方法可能出现受可查异常,要么用try-catch语句捕获,要么用throws子句声明将它抛出,不然会致使编译错误

    3)仅当抛出了异常,该方法的调用者才必须处理或者从新抛出该异常。当方法的调用者无力处理该异常的时候,应该继续抛出,而不是囫囵吞枣。

    4)调用方法必须遵循任何可查异常的处理和声明规则。若覆盖一个方法,则不能声明与覆盖方法不一样的异常。声明的任何异常必须是被覆盖方法所声明异常的同类或子类。

异常处理最佳实践

1)为可恢复的错误使用检查型异常,为编程错误使用非检查型错误。
2)在finally程序块中关闭或者释放资源
3)在堆栈跟踪中包含引发异常的缘由

        Java异常类提供了 getCause()方法来检索致使异常的缘由,这些(缘由)能够对异常的根层次的缘由提供更多的信息。该Java实践对在进行调试或排除故障大有帮助。时刻记住,若是你将一个异常包装成另外一种异常时,构造一个新异常要传递源异常。
4)始终提供关于异常的有意义的完整的信息
5)避免过分使用检查型异常
6)将检查型异常转为运行时异常

        这是在像Spring之类的多数框架中用来限制使用检查型异常的技术之一,大部分出自于JDBC的检查型异常,都被包装进DataAccessException中,而(DataAccessException)异常是一种非检查型异常。这是Java最佳实践带来的好处,特定的异常限制到特定的模块,像 SQLException 放到DAO层,将意思明确的运行时异常抛到客户层。
7)记住对性能而言,异常代价高昂
        须要记住的一件事是异常代价高昂,同时让你的代码运行缓慢。假如你有方法从ResultSet(结果集)中进行读取,这时常会抛出SQLException异常而不会移到下一元素,这将会比不抛出异常的正常代码执行的慢的多。所以最大限度的减小没必要要的异常捕捉和移动,那里没有什么固定的缘由。不要仅仅是抛出和捕捉异常,若是你能使用boolean变量去表示执行结果,可能会获得更整洁,更高性能的解决方案。修正错误的根源,避免没必要需要的异常捕捉。
8)避免catch块为空    
9)使用标准异常

        对于维护性和一致性,不论是如今仍是之后,都是最好的选择
10)记录任何方法抛出的异常
        Java提供了throw和throws关键字来抛出异常,在javadoc中用@throw记录任何方法可能会抛出的异常。若是你编写API或者公共接口,这就变得很是重要。任何方法抛出的异常都有相应的文档记录,这样你就能下意识的提醒任何使用(该方法)的人。

常见的面试问题

1 既然咱们能够用RuntimeException来处理错误,那么你认为为何Java中还存在检查型异常?

答:存在检查型异常是一个设计上的决定,受到了诸如C++等比Java更早的编程语言设计经验的影响。绝大多数检查型异常位于java.io包内,这是合乎情理的,由于在你请求了不存在的系统资源的时候,一段强壮的程序必须可以优雅的处理这种状况。经过把IOException声明为检查型异常,Java 确保了你可以优雅的对异常进行处理。另外一个可能的理由是,可使用catch或finally来确保数量受限的系统资源(好比文件描述符)在你使用后尽早获得释放

  throw 和 throws这两个关键字在java中有什么不一样?

答:throws出如今方法声明中,用来标明该成员函数可能抛出的各类异常

       throw出如今方法体中,表示抛出某种异常

3 什么是“异常链”? 

 答:“异常链”是Java中很是流行的异常处理概念,是指在进行一个异常处理时抛出了另一个异常,由此产生了一个异常链条。该技术大多用于将“ 受检查异常” ( checked exception)封装成为“非受检查异常”(unchecked exception)或者RuntimeException。顺便说一下,若是由于由于异常你决定抛出一个新的异常,你必定要包含原有的异常,这样,处理程序才能够经过getCause()和initCause()方法来访问异常最终的根源。

JDK7中对异常处理作了什么改变?

 答:JDK7中对错误(Error)和异常(Exception)处理主要新增长了2个特性,一是在一个catch块中能够出来多个异常,就像原来用多个catch块同样。另外一个是自动化资源管理(ARM), 也称为try-with-resource块。这2个特性均可以在处理异常时减小代码量,同时提升代码的可读性。

5 Java中final,finalize,finally关键字的区别

答:final和finally是Java的关键字,而finalize则是方法。final关键字在建立不可变的类的时候很是有用,只是声明这个类是final的。而finalize()方法则是垃圾回收器在回收一个对象前调用,但也Java规范里面没有保证这个方法必定会被调用。finally关键字异常处理相关的关键字

相关文章
相关标签/搜索