健全的Java语言代码必须依赖于捕获异常(Catch)或声明异常(Specify Requirement)。可能抛出确定性异常(应该是检查异常)的代码必须封装成下面两种情况之一:

代码如果无法提供必要的捕获异常或声明异常,编译将不通过。

不是所有的异常都要求捕获或声明。为了理解这一点,我们需要了解一下三种基本的异常种类,只有其中一种需要捕获或声明。

三种异常

第一种异常是检查异常(checked exception)。这些都是一个书写良好的程序可以预料和恢复的异常条件。例如,假如一个应用程序要求用户输入一个文件名称,然后把这个文件名称传入 java.io.FileReader 的构造器作为入参,以此打开这个文件。正常情况下,用户会提供一个存在的文件名,文件可读,所以 FileReader 对象创建成功,所以程序执行过程一切正常。但是有时候用户会提供不存在的文件名称,然后这个构造器就会抛出 java.io.FileNotFoundException 异常。一个书写良好的程序会捕获这个异常,并把这个错误通知给用户,可能会提示他提供一个正确的文件名。

检查异常必须要有捕获或声明。除了实现 ErrorRuntimeException及其子类的异常,其余的异常全是检查异常。

第二种异常是错误(error)。这些都是源于程序外部的异常条件,并且程序自身通常不能预料和恢复它们。例如,假如程序能根据输入的文件名打开文件,但是因为硬件或系统故障不能读取文件。这个不成功的读取过程将会抛出 java.io.IOError 错误。程序可以选择捕获这个异常,并且通知用户发生的问题——但是如果程序只是打印堆栈跟踪( stack trace)并且退出,也是有意义的。

错误不要求一定要捕获或声明。错误是实现了Error及其子类的那部分异常。

第三种异常是运行时异常(runtime exception)。这些都是源于程序内部的异常条件,并且程序自身通常不能预料和恢复它们。这通常意味着程序有BUG,比如逻辑错误或调用了错误的API。例如,考虑前面所说的把一个文件名传给 FileReader 构造器的那个程序,如果把null传给了构造器并引发了一个逻辑错误,构造器将抛出 NullPointerException 异常。应用程序可以捕获这个异常,但是消除引发这个异常的BUG会更加有意义。

运行时异常不一定要求捕获或声明。运行时异常是实现了RuntimeException及其子类的那部分异常。

错误和运行时异常统称为非检查异常(unchecked exception)。

绕过异常捕获或异常声明

有些程序员认为,在异常处理机制中,只有严重的缺陷才要求异常捕获或异常声明。并且为了绕过捕获或声明,直接用非检查异常代替检查异常。一般情况下,这是不推荐的做法。  Unchecked Exceptions — The Controversy  章节介绍了在什么情况下适合用非检查异常。





原文地址