对于异常情况,Java中使用了一种称为异常处理的错误捕获机制。
Java允许每个方法有一个候选的退出路径,当方法不能以正常的方式运行至退出语句时(不能正常退出),这时就会选择这个退出路径,通过这个退出路径来退出方法。在这种情况下,方法不会返回一个值,而是抛出(throw) 一个封装了错误信息的对象。
需要注意:
通过这种候选的退出路径退出时,这个方法会立刻退出,并不返回正常值(或任何值)。此外,也不会从调用这个方法的代码继续执行,取而代之的是,异常处理机制开始搜索一个能够处理这种异常状况的异常处理器(exception handler)。
在Java程序设计语言中,异常对象都是派生于Throwable类的一个类的实例。
异常分类:
Java中的异常层次结构如下图所示:
由图可知:所有的异常类都是Throwable的子类。而Throwable又分为两个分支:Error和Exception。
Java语言规范将异常分为两类:非检查型异常和检查型异常。
非检查型异常:
非检查型异常包括派生于Error类或RuntimeException类的所有异常。
Error类的异常描述了Java运行时系统的内部错误和资源耗尽问题。如果出现了这样的内部错误,除了通知用户,并尽力妥善的终止程序之外,我们几乎无能为力,但这种情况很少出现。因此,我们不应该抛出这种类型的对象。
继承自RuntimeException的异常包括以下问题:
- 错误的强制类型转换
- 越界的数组访问
- 访问null指针
这些运行时错误完全在我们的控制之中。我们应当谨慎一些,避免这些错误发生;因此,我们不应该抛出这种类型的对象。
也就是说,这些非检查型要么在我们的控制之外(Error),要么完全可以避免(RuntimeException);因此,我们不应该抛出非检查型异常。
检查型异常:
非检查型异常之外的所有异常(包括派生于IOException类的异常和我们自己创建的异常类)称为检查型异常。
检查型异常包括:
- 试图越过文件末尾继续读取数据
- 试图打开一个不存在的文件
- 试图根据给定的字符串查找Class对象,而这个字符串表示的类并不存在
因此,一个方法必须声明所有可能抛出的检查型异常。
需要注意的是:如果子类中覆盖了超类的一个方法,并且超类的这个方法抛出了检查型异常,那么子类方法中声明的检查型异常不能比超类方法中的异常更通用(子类方法可以抛出更特定的异常,或者根本不抛出任何异常)。如果超类被重写的方法中没有抛出任何检查型异常,那么子类方法中也不能抛出任何检查型异常。