【Java】 异常

异常分类

异常层次结构

  1. 全部的异常都是由Throwable继承而来,但在下一层理解分解为两个类Error和Exception。
  2. Error类层次结构描述了Java运行时系统的内部错误和资源耗尽错误。应用程序不该该跑出这种类型的对象。若是出现了这样的内部错误,除了通告给用户,并尽力使程序安全地终止以外,再也无能为力。
  3. 在设计Java程序时,须要关注Exception层次,这个层次结构又分解为两个分支:一个分支派生于RuntimeException;另外一个分支包含其余异常。划分两个分支的规则是:由程序错误致使的异常属于RuntimeException;而程序自己没有问题,但因为I/O错误这类问题致使的异常属于其余异常。
  4. 派生于RuntimeException的异常包含下面几种状况:
  • 错误的派生类型
  • 数组访问越界
  • 访问空指针
    不是派生于RuntimeException的异常包括:
  • 试图在文件尾部后面读取数据
  • 试图打开一个不存在的文件
  • 试图根据给定的字符串查找Class对象,而这个字符串表示的类并不存在。
  1. Java语言规范将派生于Error类或RuntimeException类的全部异常称为未检查(unchecked)异常,全部其余的异常称为已检查(checked)异常。

声明已检查的异常

方法应该在其首部声明全部可能出现抛出的异常。这样能够从首部反映出这个方法可能抛出哪类已检查异常。程序员

public FileInputStream(String name) throws FileNotFoundException
  1. 在编写本身的方法时,没必要将全部可能抛出的异常都进行声明。置于何时须要在方法中用throws子句声明异常,什么异常必须使用throws子句声明,须要记住在下面4种状况时应该抛出异常:
    1)调用一个抛出已检查异常的方法,例如,FileInputStream构造器。
    2)程序运行过程当中发现错误,而且利用throw语句抛出一个已检查异常
    3)程序出现错误,例如,a[-1]=0会抛出一个ArrayIndexOutOfBoundsException这样的未检查异常
    4)Java虚拟机和运行时库出现的内部错误
    若是出现了前两种状况之一,则必须告诉调用这个方法的程序员有可能抛出异常。由于任何一个抛出异常的方法都有多是一个死亡陷阱。若是没有处理器捕获这个异常,当前执行的线程就会结束。
  2. 对于那些可能被他人使用的Java方法,应该根据异常规范(Exception specification),在方法的首部声明这个方法可能抛出的异常。
class MyAnimation {
    public Image loadImage(String s) throws IOException {
        ...
    }
}

若是一个方法有可能抛出多个已检查异常,那么就必须在方法的首部列出全部的异常类。每一个异常类之间用逗号隔。如:编程

class MyAnimation {
    poblic Image loadImage(String s) throws FileNotFoundException, EOFException {
        ...
    }
}

可是,不须要声明Java的内部错误,即从Error继承的错误。任何程序代码都具备抛出那些异常的潜能,而咱们对其没有任何控制能力。
一样,也不该该声明从RuntimeException继承的那些未检查异常。数组

class MyAnimation{
    void drawImage(int i) throws ArrayIndexOutOfBoundsException { //bad style
        ...
    }
}

这些运行时错误彻底在咱们的控制之下。若是特别关注数组下标引起的错误,就应该讲更多的时间花费在修正程序中的错误上,而不是说明这些错误发生的可能性上。
总之,一个方法必须声明全部可能抛出的已检查异常,而未检查异常要么不可控制(Error),要么就应该避免发生(RuntimeException)。若是方法没有声明全部可能发生的已检查异常,编译器就会给出一个错误消息。
安全

捕获异常

若是某个异常发生的时候没有进行捕获,那程序就会终止执行,并在控制台上打印出异常信息,其中包括异常的类型和堆栈的内容。要想捕获一个异常,必须设置try/catch语句块。最简单的try语句块以下所示:this

try {
    code
    more code
    more code
} catch (ExceptionType e) {
    handler for this type
}

若是在try语句块中的任何代码抛出了一个在catch自娱中说明的异常类,那么
1)程序将跳过try语句块的其他代码。
2)程序将执行catch字句中的处理器代码。
若是在try语句块中的代码没有抛出任何异常,那么程序将跳过catch子句。
若是方法中的任何代码抛出了一个在catch子句中没有声明的异常类型,那么这个方法就会马上退出。
一般捕获哪些知道如何处理的异常,而将那些不知道如何处理的异常继续进行传递。若是想传递一个异常,就必须在方法的首部添加一个throws说明符,以便告知调用者这个方法可能会抛出异常。线程

捕获多个异常

在一个try语句块中能够捕获多个异常类型,并对不一样类型的异常作出不一样的处理。能够按照下列方式为每一个异常类型使用一个单独的catch子句:设计

try {
    code that might throw exceptions
} catch (FileNotFoundException e) {
    emergency action for missing files
} catch (UnknownHostException e) {
    emergency action for unknown hosts
} catch (IOException e) {
    emergency action for all other I/O problems
}

在Java SE7中,同一个catch子句中能够捕获多个异常类型。例如,假设对应缺乏文件和异常未知主机异常的动做是同样的,就能够合并catch子句:指针

try {
    code that might throw exception
} catch (FileNotFoundException  | UnknownHostException e) {
    emergency action for missing files and unknown hosts
} catch (IOException e) {
    emergency action for all other I/O problems
}

只有当捕获的异常类型彼此之间不存在子类关系时才须要这个特性。code

捕获全部异常

能够只写一个异常处理程序来捕获全部类型的异常。经过捕获异常类型的基类Exception,就能够作到这一点(事实上还有其余的基类,但Exception是同编程活动相关的基类):对象

catch(Exception e) {
    System.out.println("Caught an exception");

这将捕获全部异常,因此最好把它放在处理程序表的末尾,以防它抢在其余处理程序以前就把异常捕获了。

再次抛出异常与异常链

在catch子句中能够抛出一个异常,这样作的目的是改变异常的类型。若是开发了一个供其余程序员使用的子系统,那么,用于表示子系统故障的异常类型可能会产生多种解释。ServletException就是这样一个异常类型的例子。执行servlet的代码可能不想知道发射给你错误的细节缘由,但但愿明确地知道servlet是否有问题。
下满给出了捕获异常并将它再次抛出的基本方法:

try {
    access the database;
} catch (SQLException e) {
    throw new ServletException("..") 
}

finally子句

不论是否有异常被捕获,finally子句中的代码都被执行

相关文章
相关标签/搜索