Try-Catch-Finally語句塊執行問題
記錄一個今天某公司的面試問題,其實我問題回答對了,但是面試官問我動手驗證過沒有,這還真沒有,純理論,被懟慘了,希望自己能變得更強大。
Try-Catch-Finally語句塊執行問題。
一起來看下面這串代碼:
public class TryCatchFinally { public static void main(String[] args){ System.out.println(get()); } private static int get(){ try{ System.out.println("Try語句塊"); return 0; }catch (Exception e){ System.out.println("Catch語句塊"); return 1; }finally { System.out.println("Finally語句塊"); return 2; } } }
程序運行結果:
再來看下面這串代碼:
public class TryCatchFinally { public static void main(String[] args){ System.out.println(get()); } private static int get(){ try{ System.out.println("Try語句塊"); throw new Exception(); }catch (Exception e){ System.out.println("Catch語句塊"); return 1; }finally { System.out.println("Finally語句塊"); return 2; } } }
程序運行結果:
總結:
通過上面兩個例子可以看出:
- 無論是否在 try 語句塊中拋出異常,finally語句塊中的內容都會得到執行。
- 只有 try 語句塊中拋出異常了,catch語句塊中的內容才會得到執行。
- 但無論在 try 和 catch 語句塊中是否有返回語句,finally 語句都會得到執行,並且當 finally 語句中有 return 語句,try 和 catch 語句中的 return 語句都無法得到執行。
當然去掉 finally 中的 return 語句,try 或 catch 中的 return 語句又可以得到執行,這個可以直接在上面那個程序進行試驗。
同時 finally 語句塊中包含 return 語句,編譯器也會給出警告:finally block can not complete normally。
這是因為 finally 的 return 語句覆蓋了前面的 return 語句,是一種不合理的做法,盡量不要在 finally 中使用 return。
補充一點:
為什么 finally 語句始終都會得到執行,這里推薦一篇博客:https://blog.csdn.net/neosmith/article/details/48093427
簡單來說就是 JVM 將 finally 語句塊中的東西都復制了一遍到 try 和 catch 語句塊中,確保 finally語句塊必定會得到執行。
補充(2019/9/22)
今天又發現一個問題,來更新一下,看下面這串代碼:
public class TestMain {
public int test(){
int a=0;
try{
a++;
throw new Exception("故意的");
}catch (Exception e){
a++;
return a;
}finally {
a++;
System.out.println("a1="+a);
}
}
public static void main(String[] args){
int a=new TestMain().test();
System.out.println("a2="+a);
}
}
可以看到這個地方在test中打印的a值為 3 ,但返回值卻是 2 ,這個地方又難住了,特地查了一下資料,有這么一句話:
“Java 虛擬機會把 finally 語句塊作為 subroutine直接插入到 try 語句塊或者 catch 語句塊的控制轉移語句之前。但是,還有另外一個不可忽視的因素,那就是在執行 subroutine之前,try 或者 catch 語句塊會保留其返回值到本地變量表中。待 subroutine 執行完畢之后,再恢復保留的返回值到操作數棧中,然后通過 return 或者 throw 語句將其返回給該方法的調用者。”
也就是說這里是在 a++ 和 return 之間插入了 finally語句塊,但是在執行 finally 語句塊之前,先對 a 的值進行了保存,而之后的 finally語句塊中對 a 進行的修改只是一個值傳遞,並沒有對變量表中的 a 的值進行修改,所以也就是為什么在 finally 中 a 值為 3,而返回值 a 卻為 2。
當然這里如果將 a 改成一個對象,對對象中的某個值進行修改,也就是進行引用傳遞,則會對返回值進行修改。
這里推薦一篇博客:https://www.jianshu.com/p/011062aaa855
2019/9/22日更新
吾生也有涯,而知也無涯。