【Java异常处理】6-1 Error 和 Exception
§6-1 Error 和 Exception
本节内容将作为异常处理的第一节内容,了解 Error 和 Exception。
6-1.1 异常与错误、异常体系结构
实际工作中,遇到的情况不可能是完美的。程序在运行的过程中往往会遇到一些问题,例如打开不存在的文件、文件格式不正确、所读取的数据为空等,这称为异常(exception),即程序运行时不期而至的各种情况。
异常处理:应用程序应当正确、合理地处理可能出现的异常,而不至于程序崩溃。
异常发生在程序运行期间,它影响了程序正常的执行流程。
异常处理框架:
Java 中提供了一套异常处理框架,它把异常当作对象处理,并定义一个基类 java.lang.Throwable
作为所有异常的超类。
在 Java API 中定义了许多异常类,这些类分为两大类:错误 Error 和异常 Exception。
下图列出了含有部分异常和错误的体系结构示意:
Java 中的异常可以简单地分为以下三类:
- 编译时异常:除了
RuntimeException
及其子类,直接继承自Exception
的异常都是编译时异常。编译时异常是在编译阶段就会抛出,提醒程序员检查本地信息,这些异常不能够被简单地忽略,应当在编译阶段中处理,例如解析异常(ParseException
); - 运行时异常:
RuntimeException
以及其所有子类都是运行时异常。运行时异常是在程序运行时出现的异常,是代码参数出错导致的问题,例如数组索引越界异常(ArrayIndexOutOfBoundsException
); - 错误(error):
Error
代表的是系统级别的错误,属于严重问题,严格来说不属于异常。系统一旦出现问题,Sun 会将这些错误封装成Error
对象,而并非由程序员使用。错误并不在我们的控制和管理范围内,例如内存耗尽错误(OutOfMemoryError
)。
Java 已经预先定义好了许多异常,一般而言在开发过程中,不需要额外地自定义异常。
注意事项:
- Java 语言规范将派生于
Error
和RuntimeException
的异常称为非受查异常(unchecked),所有其他异常称为受查异常(checked); - 编译器将检查是否为所有的异常提供了异常处理器;
- 一个方法必须声明所有可能抛出的受查异常,而非受查异常要么不可控制(
Error
),要么就应当避免发生; - 若子类覆盖了超类的一个方法,子类方法所声明的异常不能比超类方法更为通用,即要么抛出更特定的异常,要么不抛出异常;
- 若超类方法没有抛出任何异常,子类方法也不能抛出任何受查异常。
6-1.2 错误 Error
Error
类对象由 JVM 生成并抛出,大多数错误与代码编写者所执行的操作无关。
Java 虚拟机运行错误(Java Virtual Machine Error),当 JVM 不再有继续执行操作所需内存资源时,将出现 OutOfMemoryError
。这些异常发生时,JVM 一般会选择终止进程。应当尽可能地避免这种情况。
还有发生在虚拟机试图执行应用时,如类定义错误(NoClassDefFoundError
)、链接错误(LinkageError
)。这些错误是不可查的,因为它们发生在应用程序的控制和处理能力之外,而且绝大多数是程序运行时所不允许的情况。尽量把我们的环境调到最优。
6-1.3 异常 Exception
在 Exception
分支中有一个重要的子类 RuntimeException
,即运行时异常,这些检查都是非受查异常,程序中可以选择捕获处理,也可以选择不处理。
这些异常一般是由程序逻辑错误、代码参数错误引起的,程序应该从逻辑角度尽可能避免这类情况发生。
与错误的区别:Error
一般指灾难性、致命性错误,是程序无法控制和处理的,当出现这些错误时,JVM 一般会选择终止进程;Exception
通常情况下是可以被程序捕获处理的,并且在程序中应该尽可能地去处理这些异常。
6-1.4 异常的作用
异常具有两个重要作用:
-
查询 bug 的关键参考信息;
抛出异常时,控制台会打印出抛出异常的方法、异常名称,以及抛出异常的原因(英文);
同时,控制台还会显示出异常抛出所在的代码行,告知程序员问题所在位置,方便定位,一般建议从下往上看。
以标准 Java Bean 类
Student
为例,在主方法中:Student[] students = new Student[3]; System.out.println(students[0].getName());
运行,则会抛出异常:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "com.zebt.exceptions.Student.getName()" because "students[0]" is null at com.zebt.exceptions.Test.main(Test.java:7)
这一段信息就告诉了我们异常抛出的方法、异常名称、抛出原因、问题所在代码行。
-
作为方法内部的一种特殊返回值,通知调用者底层执行情况。
当被调用方法所接受的参数非法或遭遇到一些其他情况,被调用方法应当向调用者告知情况。此时可以抛出异常,告知调用者底层执行情况,调用者则应当根据可能抛出的异常,对应地处理异常。
这一部分内容在下一节中介绍。