第12章 异常处理和文本I/O
12.1 引言
异常处理使得程序可以处理非预期的情景,并且继续正常的处理。
在程序运行过程中,如果JVM检测出一个不可能执行的操作,就会出现运行时错误(runtime error)。
在Java中,运行时错误会作为异常抛出。异常就是一种对象,表示阻止正常进行程序执行的错误或情况。如果异常没有被处理,那么程序将会非正常终止。
12.2 异常处理概述
异常是从方法抛出的。方法的调用者可以捕获以及处理该异常。
throw语句的执行称为抛出一个异常(throwing an exception)。异常就是一个从异常类创建的对象。
当异常被抛出时,正常的执行流程就被中断。就像它的名字所提示的,“抛出异常”就是将异常从一个地方传递到另一个地方。调用方法的语句包含在一个try块和catch块。try块包含了正常情况下执行的代码。异常被catch块所捕获。catch块中的代码执行以处理异常。之后,catch块之后的语句被执行。
throw语句类似于方法的调用,但不同于调用方法的是,它调用的是catch块。从某种意义上讲,在执行完catch块之后,程序控制不返回到throw语句;而是执行catch块后的下一条语句。
catch头部
catch (ArithmeticExeption ex)
标识符ex的作用很像是方法中的参数。所以,这个参数称为catch块的参数。ex之前的类型指定了catch块可以捕获的异常类型。一旦捕获该异常,就能从catch块体中的参数访问这个抛出的值。
总之,一个try-throw-catch块的模板可能会如下所示:
try {
Code to run;
A statement or a method that may throw an exception;
More code to run;
}
catch (type ex) {
Code to process the exception;
}
一个异常可能是通过try块中的throw语句直接抛出,或者调用一个可能会抛出异常的方法而抛出。
使用异常处理能使方法抛出一个异常给它的调用者,并由调用者处理该异常。如果没有这个能力,那么被调用的方法就必须自己处理异常或者终止该程序。被调用的方法通常不知道在出错的情况下该做些什么。异常处理最根本的优势就是将检测错误(被调用的方法完成)从处理错误(由调用方法完成)中分离出来。
12.3 异常类型
异常是对象,而对象都采用来类来定义。异常的根类是java.lang.Throwable。
类名Error、Exception和RuntimeException有时候容易引起混淆。这三种类都是异常,这里讨论的错误都发生在运行时。
Throwable类是所有异常类的根。所有的类Java异常类都直接或者间接地继承自Throwable。可以通过继承Exception或者Exception的子类来创建自己的异常类。
这些异常类可以分为三种主要类型:系统错误、异常和运行时异常。
系统错误(system error)是由Java虚拟机抛出的,用Error类表示。Error类描述的是内部系统错误。这样的错误很少发生。如果发生,除了通知用户以及尽量稳妥地终止程序外,几乎什么也不能做。
类 | 可能引起异常的原因 |
---|---|
LinkageError | 一个类对另一个类有某种依赖性,但是在编译前者后,后者进行了修改,变得不兼容 |
VirtualMachineError | Java虚拟机崩溃,或者运行所必需的资源已经耗尽 |
异常(exception)是用Exception类表示的,它描述的是由程序和外部环境所引起的错误,这些错误能被程序捕获和处理。
类 | 可能引起异常的原因 |
---|---|
ClassNotFoundException | 试图使用一个不存在的类。例如,如果试图使用命令java来运行一个不存在的类,或者程序要调用三个类文件而只能找到两个,都会发生这种异常。 |
IOException | 同输入/输出相关的操作,例如,无效的输入、读文件时超过文件尾,打开一个不存在的文件等。IOException的子类的例子有InterruptedIOException、EOFException(EOF是End Of File的缩写)和FileNotFoundException |
运行时异常(runtime exception)是用RuntimeException类表示的,它描述的是程序设计错误,例如,错误的是类型转换,访问一个越界数组或数值错误。运行时异常通常是由Java虚拟机抛出的。
类 | 可能引起异常的原因 |
---|---|
ArithmeticException | 一个整数除以0。注意,浮点数的算术运算不抛出异常。 |
NullPointerException | 试图通过一个null引用变量访问一个对象 |
IndexOutOfBoundsException | 数组的下标超出范围 |
IllegalArgumentException | 传递给方法的参数非法或不合适 |
RuntimeException、Error以及它们的子类都称为免检异常(unceked exception)。所有其他异常都称为必检异常(checked exception),意思是编译器会强制程序员检查并通过try-catch块处理它们,或者在方法头进行声明。
在大多数情况下,免检异常都会反映出程序设计上不可恢复的逻辑错误。例如,如果通过一个引用变量访问一个对象之前并未将一个对象赋值给它,就会抛出NullPointerException异常;如果访问一个数组的越界元素,就会抛出IndexOutOfBoundsException异常。这些都是程序中必须纠正的逻辑