5.3 如何抛出异常
在可以捕获异常之前,一些代码必须抛出一个异常。任何代码都可能会抛出异常,有些是你自己的代码,有些是其他人编写的包或Java运行时环境的代码。无论是什么引发的异常,它总是通过throw语句抛出。
Java平台提供了许多异常类,这些类都是Throwable类的后代,并且都允许程序区分在程序执行期间可能发生的各种类型的异常。
开发者还可以创建自己的异常类来表示在编写的类中可能发生的问题。事实上,如果是包的开发人员,可能必须创建自己的一组异常类,以允许用户区分包中可能发生的错误与Java平台或其他包中发生的错误。
5.3.1 throw语句
所有方法都使用throw语句抛出异常。throw语句需要一个参数——Throwable对象。Throwable对象是Throwable类中任何子类的实例。以下是一个throw语句的例子。
让我们来看一下上下文中的throw语句。以下pop方法取自实现公共堆栈对象的类。该方法从堆栈中删除顶层元素并返回对象。
pop方法将会检查栈中的元素。如果栈是空的(它的size等于0),那么pop实例化一个EmptyStackException对象(java.util的成员)并抛出它。EmptyStackException继承自java.lang.Throwable类。
注意
pop方法的声明不包含throws子句。EmptyStackException不是已检查异常,因此不需要pop来声明它可能发生。
5.3.2 Throwable类及其子类
继承自Throwable类的对象包括直接后代(直接从Throwable类继承的对象)和间接后代(从Throwable类的子代或孙代继承的对象)。图5-2说明了Throwable类及其重要的子类的类层次结构。
图5-2 Throwable类及其子类
正如图5-2所示,Throwable有两个直接的后代——Error和Exception。
5.3.3 Error类
当Java虚拟机中发生动态链接故障或其他硬故障时,虚拟机会抛出Error。Error在正常情况下不大可能出现,绝大部分的Error都会导致程序处于非正常、不可恢复状态,比如常见的OutOfMemoryError。
在一般的程序中,通常不捕获或抛出Error。
5.3.4 Exception类
大多数程序抛出和捕获从Exception类派生的对象。Exception表示发生了问题,但它不是严重的系统问题。我们编写的大多数程序将抛出并捕获Exception而不是Error。
Java平台定义了Exception类的许多后代,这些后代表示可能发生的各种类型的异常。例如,IllegalAccessException表示找不到特定方法,NegativeArraySizeException表示程序尝试创建一个负大小的数组等。
Exception的子类RuntimeException主要用于指示不正确使用API产生的异常。RuntimeException的一个示例是NullPointerException,当方法尝试通过空引用访问对象的成员时会发生此空指针异常。
大多数应用程序不应该抛出运行时异常或RuntimeException的子类,详情可参见5.6节的内容。