# 异常分类
所有的异常都继承自 Throwable 类。
Error 类描述了 Java 运行时系统的内部错误和资源耗尽错误。此种异常不应该由程序抛出,若出现这种异常,应通告给用户并尽力使程序安全地终止。
Exception 类是应用程序抛出的错误。Exception 类包括 IO 异常类和运行时异常类。
RuntimeException 类包括错误的类型转换、数组访问越界和访问 null 指针。在程序中应该杜绝此类异常的发生。
IOException 类包括试图在文件尾部后面读取数据、试图打开一个不存在的文件和试图根据给定的字符串查找 Class 对象,而这个字符串表示的类并不存在。此类异常需要在程序中手动抛出。
Error 类或 RuntimeException 类的所有异常称为不可查异常,所有其他异常称为可查异常。一个方法必须声明所有可能抛出的可查异常,而非可查异常要么不可控制,要么就应该避免发生。
# 使用异常机制的技巧
异常处理不能代替简单的测试。
如果要对一个栈进行退栈操作,可能存在的异常是这个栈是一个空栈。那么我们最好使用
!s.empty()
来检查该栈是否为空,若不为空再进行退栈,而不应该使用抛出异常的方式。//right,运行时间 646ms
if (!s.empty()) {
s.pop();
}
//error,运行时间 21739ms
try {
s.pop();
} catch (EmptyStackException e) {
...
}
不要过分地细化异常
对一个栈进行退栈操作,然后把这个值放在一个文件里。这两步操作都有可能出现异常,如果分别进行捕获,当第一步出现异常时,程序会继续去执行第二个操作,这样就不没有什么意义了,我们希望下一步操作也终止。
//error,代码臃肿
PrintStream out;
Stack s;
for (i = 0;i < 100; i++) {
try {
n = s.popO;
} catch (EmptyStackException e) {
...
}
try {
out.writelnt(n);
} catch (IOException e) {
...
}
}
//right,任何一个操作出现问题,整个任务可以取消
try {
for (i = 0; i < 100; i++) {
n = s.popO ;
out.writelnt(n);
}
} catch (IOException e) {
...
} catch (EmptyStackException e) {
...
}
利用异常层次结构
不要只抛出 RuntimeException 异常,应该寻找更加适合的子类或创建自己异常类;不要只捕获 Thowable 异常,否则会使程序代码更难读和维护;不要为错误逻辑抛出异常;可将一种异常转化为另一种更合适的异常,例如,在解析某个文件中的一个整数时,捕获 NumberFormatException 异常,然后将它转换成 IOException 或 MySubsystemException 的子类。
不要压制异常
若一个方法抛出一个异常,另一个方法在调用它的时候,就必须对这个异常进行处理,否则编译不会通过。但是这个异常可能
在检测错误时要苛刻一点
假如要从栈中拿出一个值,然后进行操作。若栈是一个空栈,就会出现异常。我们会在代码中进行检查,是返回一个 null 值呢,还是抛出一个异常呢,此时不抛异常,后面也要抛一个空指针异常,所以最好是在前面就抛异常,这样抛出来的异常更清晰明了,后续也不会再执行一些无用的操作。
不要羞于传递异常
有时候传递这个异常比捕获这个异常更为合适,传递下去可以让更高层次的方法通知用户发生了错误。