finally中使用return会吃掉catch中抛出的异常&finally中抛出的异常会吃掉catch中的return

来源:互联网 发布:淘宝话术技巧 编辑:程序博客网 时间:2024/05/16 20:30
1:当一个方法既有throws又有catch的时候,直接catch异常的引用不再throws
2:finally中的return语句会使异常丢失
3:finally中重新抛出的异常会覆盖catch的异常


今天学习大神的文章:深入理解java异常处理机制 学到一个有意思的知识点。如果在finally中使用return会吃掉catch中抛出的异常。

看例子:

[java] view plaincopy
  1. public class TestException {  
  2.     public TestException() {  
  3.     }  
  4.   
  5.     boolean testEx() throws Exception {  
  6.         boolean ret = true;  
  7.         try {  
  8.             ret = testEx1();  
  9.         } catch (Exception e) {  
  10.             System.out.println("testEx, catch exception");  
  11.             ret = false;  
  12.             throw e;  
  13.         } finally {  
  14.             System.out.println("testEx, finally; return value=" + ret);  
  15.             return ret;  
  16.         }  
  17.     }  
  18.   
  19.     boolean testEx1() throws Exception {  
  20.         boolean ret = true;  
  21.         try {  
  22.             ret = testEx2();  
  23.             if (!ret) {  
  24.                 return false;  
  25.             }  
  26.             System.out.println("testEx1, at the end of try");  
  27.             return ret;  
  28.         } catch (Exception e) {  
  29.             System.out.println("testEx1, catch exception");  
  30.             ret = false;  
  31.             throw e;  
  32.         } finally {  
  33.             System.out.println("testEx1, finally; return value=" + ret);  
  34.             return ret;  
  35.         }  
  36.     }  
  37.   
  38.     boolean testEx2() throws Exception {  
  39.         boolean ret = true;  
  40.         try {  
  41.             int b = 12;  
  42.             int c;  
  43.             for (int i = 2; i >= -2; i--) {  
  44.                 c = b / i;  
  45.                 System.out.println("i=" + i);  
  46.             }  
  47.             return true;  
  48.         } catch (Exception e) {  
  49.             System.out.println("testEx2, catch exception");  
  50.             ret = false;  
  51.             throw e;  
  52.         } finally {  
  53.             System.out.println("testEx2, finally; return value=" + ret);  
  54.             return ret;  
  55.         }  
  56.     }  
  57.   
  58.     public static void main(String[] args) {  
  59.         TestException testException1 = new TestException();  
  60.         try {  
  61.             testException1.testEx();  
  62.         } catch (Exception e) {  
  63.             e.printStackTrace();  
  64.         }  
  65.     }  
  66. }  

运行结果:

i=2
i=1
testEx2, catch exception
testEx2, finally; return value=false
testEx1, finally; return value=false
testEx, finally; return value=false

有点奇怪,下层方法抛出的异常竟然没有被捕获。

如果把return和throw放在一起,直接会提示错误。"Unreachable statement"(无法被执行).

然而finally却可以成功骗过编译器让两者并存(是不是可以算是编译器的一个小bug呢),结果是后执行的会覆盖前者。finally如果有return会覆盖catch里的throw,同样如果finally里有throw会覆盖catch里的return。

进而如果catch里和finally都有return finally中的return会覆盖catch中的。throw也是如此。

这样就好理解一些了,retrun和throw都是使程序跳出当前的方法,自然就是冲突的。如果非要跳出两次那么后者会覆盖前者。


在《Java编程思想》中也有类似的例子,放在这里一起讨论。

“9.6.2 缺点:丢失的违例
一般情况下,Java的违例实施方案都显得十分出色。不幸的是,它依然存在一个缺点。尽管违例指出程序里存在一个危机,而且绝不应忽略,但一个违例仍有可能简单地“丢失”。在采用finally从句的一种特殊配置下,便有可能发生这种情况”

[java] view plain copy
  1. class VeryImportantException extends Exception{  
  2.     public String toString(){  
  3.         return "A very important exception";  
  4.     }  
  5. }  
  6.   
  7. class HoHumException extends Exception{  
  8.     public String toString() {  
  9.         return "A trivial exception";  
  10.     }  
  11. }  
  12. public class LostMessage {  
  13.     void f() throws VeryImportantException{  
  14.         throw new VeryImportantException();  
  15.     }  
  16.   
  17.     void dispose() throws HoHumException{  
  18.         throw new HoHumException();  
  19.     }  
  20.   
  21.     public static void main(String[] args) throws Exception{  
  22.         LostMessage lm = new LostMessage();  
  23.         try{  
  24.             lm.f();  
  25.         }finally {  
  26.             lm.dispose();  
  27.         }  
  28.               
  29.     }  
  30. }  

输出:

Exception in thread "main" A trivial exception
at com.test.exception.LostMessage.dispose(LostMessage.java:24)
at com.test.exception.LostMessage.main(LostMessage.java:32)

“这是一项相当严重的缺陷,因为它意味着一个违例可能完全丢失。而且就象前例演示的那样,这种丢失显得非常“自然”,很难被人查出蛛丝马迹。而与此相反,C++里如果第二个违例在第一个违例得到控制前产生,就会被当作一个严重的编程错误处理。或许Java以后的版本会纠正这个问题(上述结果是用Java 1.1生成的)。”

书中的例子更加犀利,我们尽量避免这样的事情发生吧。

0 0