1. 程式人生 > >java異常處理中的return和throw

java異常處理中的return和throw

如果把return和throw放在一起,直接會提示錯誤。"Unreachable statement"(無法被執行).

然而finally卻可以成功騙過編譯器讓兩者並存(是不是可以算是編譯器的一個小bug呢),結果是後執行的會覆蓋前者。

finally如果有return會覆蓋catch裡的throw,同樣如果finally裡有throw會覆蓋catch裡的return。

進而如果catch裡和finally都有return finally中的return會覆蓋catch中的。throw也是如此。

這樣就好理解一些了,retrun和throw都是使程式跳出當前的方法,自然就是衝突的。如果非要跳出兩次那麼後者會覆蓋前者。

 

 

 
  1. public class T {

  2.  
  3. public T() {

  4.  
  5. }

  6.  
  7. boolean testEx() throws Exception {

  8.  
  9. boolean ret = true;

  10.  
  11. try {

  12.  
  13. ret = testEx1();

  14.  
  15. } catch (Exception e) {

  16.  
  17. System.out.println("testEx, catch exception");

  18.  
  19. ret = false;

  20.  
  21. throw e;

  22.  
  23. } finally {

  24.  
  25. System.out.println("testEx, finally; return value=" + ret);

  26.  
  27. return ret;

  28.  
  29. }

  30.  
  31. }

  32.  
  33. boolean testEx1() throws Exception {

  34.  
  35. boolean ret = true;

  36.  
  37. try {

  38.  
  39. ret = testEx2();

  40.  
  41. if (!ret) {

  42.  
  43. return false;

  44.  
  45. }

  46.  
  47. System.out.println("testEx1, at the end of try");

  48.  
  49. return ret;

  50.  
  51. } catch (Exception e) {

  52.  
  53. System.out.println("testEx1, catch exception");

  54.  
  55. ret = false;

  56.  
  57. throw e;

  58.  
  59. }

  60.  
  61. finally {

  62.  
  63. System.out.println("testEx1, finally; return value=" + ret);

  64.  
  65. return ret;

  66.  
  67. }

  68.  
  69. }

  70.  
  71. boolean testEx2() throws Exception {

  72.  
  73. boolean ret = true;

  74.  
  75. try {

  76.  
  77. int b = 12;

  78.  
  79. int c;

  80.  
  81. for (int i = 2; i >= -2; i--) {

  82.  
  83. c = b / i;

  84.  
  85. System.out.println("i=" + i);

  86.  
  87. }

  88.  
  89. return true;

  90.  
  91. } catch (Exception e) {

  92.  
  93. System.out.println("testEx2, catch exception");

  94.  
  95. ret = false;

  96.  
  97. throw e;

  98.  
  99. }

  100. finally {

  101.  
  102. System.out.println("testEx2, finally; return value=" + ret);

  103.  
  104. //return ret;

  105.  
  106. }

  107. }

  108.  
  109. public static void main(String[] args) {

  110.  
  111. T testException1 = new T();

  112.  
  113. try {

  114.  
  115. testException1.testEx();

  116.  
  117. } catch (Exception e) {

  118.  
  119. e.printStackTrace();

  120.  
  121. }

  122.  
  123. }

  124.  
  125. }

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

 

try-catch-finally程式塊的執行流程

首先執行的是try語句塊中的語句,這時可能會有以下三種情況:

1.              如果try塊中所有語句正常執行完畢,那麼finally塊的居於就會被執行,這時分為以下兩種情況:

        如果finally塊執行順利,那麼整個try-catch-finally程式塊正常完成。

        如果finally塊由於原因R突然中止,那麼try-catch-finally程式塊的結局是“由於原因R突然中止(completes abruptly)”

2.              如果try語句塊在執行過程中碰到異常V,這時又分為兩種情況進行處理:

        如果異常V能夠被與try相應的catch塊catch到,那麼第一個catch到這個異常的catch塊(也是離try最近的一個與異常V匹配的catch塊)將被執行;這時就會有兩種執行結果:

        如果catch塊執行正常,那麼finally塊將會被執行,這時分為兩種情況:

        如果finally塊執行順利,那麼整個try-catch-finally程式塊正常完成。

        如果finally塊由於原因R突然中止,那麼try-catch-finally程式塊的結局是“由於原因R突然中止(completes abruptly)”

        如果catch塊由於原因R突然中止,那麼finally模組將被執行,分為兩種情況:

        如果如果finally塊執行順利,那麼整個try-catch-finally程式塊的結局是“由於原因R突然中止(completes abruptly)”。

        如果finally塊由於原因S突然中止,那麼整個try-catch-finally程式塊的結局是“由於原因S突然中止(completes abruptly)”,原因R將被拋棄。

雖然我們在testEx2中使用throw e丟擲了異常,但是由於testEx2中有finally塊,而finally塊的執行結果是complete abruptly的。因為return也是一種導致complete abruptly的原因之一,所以整個try-catch-finally程式塊的結果是“complete abruptly”,所以在testEx1中呼叫testEx2時是捕捉不到testEx1中丟擲的那個異常的,而只能將finally中的return 結果獲取到。當然這種情況是可以避免的,以testEx2為例:如果你一定要使用finally而且又要將catch中 throw的e在testEx1中被捕獲到,那麼你去掉testEx2中的finally中的return就可以了。如果將testEx2()中的

 

 

 
  1. finally {

  2.  
  3. System.out.println("testEx2, finally; return value=" + ret);

  4.  
  5. //return ret;

  6.  
  7. }

修改為

 

 

 
  1. finally {

  2.  
  3. System.out.println("testEx2, finally; return value=" + ret);

  4.  
  5. return ret;

  6.  
  7. }

那麼執行結果:

 

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

try-catch-finally程式塊中的return

從上面的try-catch-finally程式塊的執行流程以及執行結果一節中可以看出無論try或catch中發生了什麼情況,finally都是會被執行的,那麼寫在try或者catch中的return語句也就不會真正的從該函式中跳出了,它的作用在這種情況下就變成了將控制權(語句流程)轉到 finally塊中;這種情況下一定要注意返回值的處理。

例如,在try或者catch中return false了,而在finally中又return true,那麼這種情況下不要期待你的try或者catch中的return false的返回值false被上級呼叫函式獲取到,上級呼叫函式能夠獲取到的只是finally中的返回值,因為try或者catch中的return 語句只是轉移控制權的作用。