finally中使用return會喫掉catch中拋出的異常

原文地址:http://blog.csdn.net/tiantiandjava/article/details/46777051



今天學習大神的文章:深入理解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從句的一種特殊配置下,便有可能發生這種情況”

  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生成的)。”

書中的例子更加犀利,我們儘量避免這樣的事情發生吧。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章