【Java疑難雜症】有return的情況下try catch finally的執行順序


  有這樣一個問題,異常處理大家應該都不陌生,類似如下代碼:

 1 public class Test {  2     public static void main(String[] args) {  3         int d1 = 0;  4         int d2 = 1;  5         try {  6             d2--;  7             d1 = 1 / d2;  8             System.out.println("try");  9         }catch (Exception e){ 10             System.out.println("Catch An Exception."); 11         }finally { 12             System.out.println("finally"); 13  } 14  } 15 }

  運行到第7行的時候,會出現算術異常,try語句塊捕獲到這個異常,然后開始執行catch語句塊中的內容,最后執行,finally語句塊中的內容,因此輸出如下:

Catch An Exception. finally

  但是,如果try,catch,finally語句中有return的時候,會怎樣呢?

  我們都知道,finally語句塊是不論如何都會執行的,那三個塊中的return,會先返回誰呢?我們來進行一下測試:

public class Test { public static void main(String[] args) { int i = Test.getReturn(); System.out.println(i); } public static int getReturn(){ int a = 0; int d1 = 0; int d2 = 1; try {
      //try語句塊中沒有發生異常 a
= 10; d1 = 1 / d2; return a; }catch (Exception e){ a = 20; System.out.println("Catch An Exception."); return a; }finally { a = 30; System.out.println("finally"); return a; } } }

  這里的try語句塊中沒有發生異常,那么執行順序如何呢?在try中的return是直接返回嗎?finally的return該怎樣處理呢?先讓我們看一下結果:

finally
30

  結果是執行完成finally語句塊之后,使用的是finally語句塊中的a,而不是try語句塊中的a。

  那如果try中出現異常呢?我們改動一下:

public class Test { public static void main(String[] args) { int i = getReturn(); System.out.println(i); } public static int getReturn(){ int a = 0; int d1 = 0; int d2 = 1; try { a = 10; d1 = 1 / (--d2); return a; }catch (Exception e){ a = 20; System.out.println("Catch An Exception."); return a; }finally { a = 30; System.out.println("finally"); return a; } } }

  好的,現在try中出現了算術異常,catch語句塊將被執行,然后再執行finally語句塊,這樣的話返回結果如何呢?

Catch An Exception. finally
30

  還是返回30,也就是finally中a的值

  如果去掉finally中的return會怎樣?

public class Test { public static void main(String[] args) { int i = getReturn(); System.out.println(i); } public static int getReturn(){ int a = 0; int d1 = 0; int d2 = 1; try { a = 10; d1 = 1 / (--d2); return a; }catch (Exception e){ a = 20; System.out.println("Catch An Exception."); return a; }finally { a = 30; System.out.println("finally"); //return a;
 } } }

  輸出如下:

Catch An Exception. finally
20

  返回的是catch語句塊中的a。先執行catch語句塊中的代碼,finally語句雖然執行了,a的值應該也被修改成30了,但實際返回的卻是20,。

  我們再來做一個測試,把catch和finally語句塊中的return都注釋掉,來看看返回情況:

public class Test { public static void main(String[] args) { int i = getReturn(); System.out.println(i); } public static int getReturn(){ int a = 0; int d1 = 0; int d2 = 1; try { a = 10; d1 = 1 / (d2); return a; }catch (Exception e){ a = 20; System.out.println("Catch An Exception."); //return a;
        }finally { a = 30; System.out.println("finally"); //return a;
 } return a; } }

  輸出如下:

finally
10

  所以finally中雖然修改了a的值,但實際返回的是修改之前的值。也就是相當於程序先用一個瓶子將try中的return的值裝起來,后面不管finally如果修改a的值,返回值都不會變,但這只是因為返回的是基本數據類型,如果是引用類型,還是有點區別的,來看個栗子。

  先聲明一個Stu類:

public class Stu { String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }

  測試一下:

public class Test { public static void main(String[] args) { Stu stu = getReturn(); System.out.println(stu.getName()); } public static Stu getReturn(){ Stu stu = new Stu(); int d1 = 0; int d2 = 1; try { stu.setName("1"); d1 = 1 / (d2); return stu; }catch (Exception e){ stu.setName("2"); System.out.println("Catch An Exception.");
        }finally { stu.setName("3"); System.out.println("finally");
 } return stu; } }

  輸出如下:

finally
3

  所以你看,現在還是變成了finally中的修改值,所以瓶子里裝的只是變量中的內容,只能保證這個內容不會變,如果是引用變量,變量中存儲的是引用對象的地址,finally中對引用對象的修改還是會影響到返回對象的。

  所以結論其實很簡單,try,catch,finally語句塊的return的優先級由低到高,先執行try中return之前的語句,如果遇到異常,則執行catch語句中return之前的代碼,最后執行finally語句塊,finally語句塊中如果有return,那么程序就會提前返回,如果沒有,則返回catch語句塊中的return,如果沒有遇到異常,則直接執行finally中的語句塊,再看finally語句塊中是否有return來決定返回結果。

  結論:
  1、不管是否出現異常,finally塊中的代碼都會執行;
  2、當try和catch中有return時,finally仍然會執行,finally中的return優先級大於catch大於try;
  3、finally是在return后面的表達式運算后執行的(此時並沒有返回運算后的值,而是先把要返回的值保存起來,管finally中的代碼怎么樣,返回的值都不會改變,任然是之前保存的值),所以函數返回值是在finally執行前確定的;
  4、finally中最好不要包含return,否則程序會提前退出,返回值不是try或catch中保存的返回值。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM