捕获或者声明(Catch or Specify Requirement)

有效的Java编程语言代码必须满足异常的捕获或者声明(Catch or Specify Requirement) 。 可能抛出异常的代码必须是下列两种处理方式之一:

  • 使用 try 捕获异常。try 必须提供处理器来处理异常,详见“异常捕获和处理”;
  • 通过在方法签名中利用 throws 关键字,声明异常可以将异常抛出,将异常传递给调用者,自己可以不用处理。详见“通过方法声明异常抛出”。

所编写的代码如果不满足捕获或者声明异常将不会编译成功。

并非所有的异常都满足捕获或者声明异常 的约束。 为了理解为什么,我们需要看看三个基本类别的例外,其中只有一个符合要求。

三个不同的异常

1. 已检查异常(checked exception)

已检查异常是一个良好的应用程序应该预期和恢复的特殊条件。例如,假设应用程序提示用户输入文件名,然后通过将名称传递给java.io.FileReader的构造函数来打开该文件。通常,用户提供现有可读文件的名称,这样FileReader对象才能构造成功,应用程序才能执行正常进行。但有时用户提供不存在的文件的名称,并且构造函数抛出java.io.FileNotFoundException。一个编写良好的程序将捕获此异常并通知用户该错误,并可能地提示用户需要修正文件名。

已检查异常受限于捕获或者声明异常。除了 Error、RuntimeException 和它们的子类以外,所有异常都是已检查异常。

2. 错误(error)

错误是应用程序外部的特殊条件,是应用程序通常无法预期或恢复的。例如,假设应用程序成功打开文件以进行输入,但由于硬件或系统故障而无法读取该文件。未成功读取将抛出java.io.IOError。应用程序可能选择捕获此异常,以便将该问题通知给用户 ,当然程序也可以选择打印堆栈跟踪并退出。

错误不受捕获或者声明异常的限制。错误是由 Error 及其子类指示的异常。

3. 运行时异常(runtime exception)

运行时异常是应用程序内部的特殊情况,应用程序通常无法预期或恢复。这些通常表示编程错误,例如逻辑错误或API的不当使用。例如,考虑前面描述的将文件名传递给FileReader的构造函数的应用程序。如果一个逻辑错误导致一个null传递给构造函数,构造函数将抛出NullPointerException。应用程序可以捕获此异常,但也可能更有意义,以消除导致异常发生的错误。

运行时异常不受捕获或者声明异常的限制。运行时异常是由 RuntimeException 及其子类指示的异常。

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

绕过捕获或者声明异常

一些程序员认为不受捕获或者声明异常是异常机制的严重缺陷,并试图通过使用未检查的异常代替已检查异常来绕过它。 一般来说,这是不推荐。 “未检查的异常”部分讨论何时使用未检查异常是恰当的。