《java编程思想》中曾指出异常丢失问题,并期待在未来版本中修正这个问题。遗憾的是在我测试的JDK8.0版本中,这个问题仍然存在:
public class Demo1 {
void f1() throws MyException1{
throw new MyException1();
}
void f2() throws MyException2{
throw new MyException2();
}
public static void main(String[] args) {
Demo1 d = new Demo1();
try{
try {
d.f1();
}finally {
d.f2();
}
}catch (Exception e){
System.out.println(e);
}
}
}
class MyException1 extends Exception{
@Override
public String toString() {
return "MyException1...";
}
}
class MyException2 extends Exception{
@Override
public String toString() {
return "MyException2...";
}
}
输出结果为:
MyException2...
可见MyException1被悄无声息地吞掉了。
原因可以归结为:调用某一个抛出异常的方法,原则上必须catch该异常,但是可以把该异常处理块放在一个更大的try块里面,由外部的try块来处理异常。这样字块finally中抛出的异常会“覆盖”之前的异常,从而导致前一个异常丢失。下面可以简单证实“异常覆盖”问题:
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
int a = 1/0;
}finally {
String s = null;
s.length();
}
}
输出结果为:
Exception in thread "main" java.lang.NullPointerException
at huli.Demo.main(Demo.java:13)
可见只抛出了空指针异常,而 / by zero 异常丢失了,或者说被finally字句的异常覆盖了。
另外,finally中的return语句也可能导致异常丢失:
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
int a = 1/0;
Class.forName("abcd");
} catch (ClassNotFoundException e) {
System.out.println("aaa");
}finally {
System.out.println("bbb");
return;
}
}
输出为:
bbb
同样导致了异常丢失问题。
或许有效的建议:
1)使用try...finally块时要格外小心,如果可以的话,尽量使用完整的try...catch...finally
2)尽量不要在finally块中写return