有這樣一個問題,異常處理大家應該都不陌生,類似如下代碼:
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中保存的返回值。