陷阱 - 捕获 Throwable 异常错误或 RuntimeException
对于没有经验的 Java 程序员的一个常见的思维模式是异常情况是有问题或负担,并处理这个最好的办法是一网打尽 1 ,尽快。这导致代码如下:
....
try {
InputStream is = new FileInputStream(fileName);
// process the input
} catch (Exception ex) {
System.out.println("Could not open file " + fileName);
}
上面的代码有一个重大缺陷。catch
实际上会捕获比程序员期望的更多异常。假设 fileName
的值是 null
,由于应用程序中的其他地方的错误。这将导致 FileInputStream
构造函数抛出 NullPointerException
。处理程序将捕获此信息,并向用户报告:
Could not open file null
这是无益和混乱的。更糟糕的是,假设它是处理输入代码引发意外异常(已检查或未选中!)。现在,用户将获得针对打开文件时未发生的问题的误导性消息,并且可能与 I / O 完全无关。
问题的根源是程序员为 Exception
编写了一个处理程序。这几乎总是一个错误:
- 捕获
Exception
将捕获所有已检查的异常,以及大多数未经检查的异常。 - 捕获
RuntimeException
将捕获大多数未经检查的异常。 - 捕获
Error
将捕获未经检查的异常,这些异常表示 JVM 内部错误。这些错误通常无法恢复,因此不应被捕获。 - 捕获
Throwable
将捕获所有可能的异常。
捕获过多一组异常的问题是处理程序通常无法正确处理所有异常。在 Exception
等的情况下,程序员很难预测可以捕获的内容; 即期待什么。
一般情况下,正确的解决办法是处理该异常被抛出。例如,你可以捕获它们并在原地处理它们:
try {
InputStream is = new FileInputStream(fileName);
// process the input
} catch (FileNotFoundException ex) {
System.out.println("Could not open file " + fileName);
}
或者你可以通过封闭方法将它们声明为 thrown
。
捕捉 Exception
是合适的情况很少。通常出现的唯一一个是这样的:
public static void main(String[] args) {
try {
// do stuff
} catch (Exception ex) {
System.err.println("Unfortunately an error has occurred. " +
"Please report this to X Y Z");
// Write stacktrace to a log file.
System.exit(1);
}
}
在这里,我们真正想要处理所有异常,所以捕捉 Exception
(甚至 Throwable
)是正确的。
1 - 也称为 Pokemon 异常处理 。