【JAVA】當finally遇上return
當finally遇上return
剛學異常捕獲機制時,會有這麼一個問題,當try中出現return語句時,那麼finally語句還會不會執行呢?
先從一道程式碼題入手,那麼該段程式碼的輸出是什麼呢?
public static int testFinally1() { int i = 0; try { ++i; return i; } catch (Exception e) { ++i; return i; } finally { System.out.println("finally"); } }
輸出結果截圖
可以看得出,try語句塊中即使有了return語句,finally也照樣執行了,但從執行的結果來看,finally先執行,然後再執行return 0的語句。
由此道題總結出一下兩點:
(1)在java的異常捕獲機制中,finally的語句塊保證了不管遇到什麼情況,finally語句塊一定被執行,除非突然出現崩潰或者是System.exit(),這兩種情況不談,太特殊了。
(2)當程式執行到return語句中,就意味著結束對當前函式的呼叫並跳出這個函式體,任何語句要執行都只能在return前執行,因此finally語句塊中程式碼也是在return前執行的。
從深層理解來看,當執行到try中的return語句時,return關鍵詞會先把i放入到一個臨時的棧空間中,然後再去執行finally中的語句,執行完畢後,再把臨時棧空間中的值返回。
如果在finally中修改i的值呢?
public static int testFinally1() { int i = 0; try { ++i; return i; } catch (Exception e) { ++i; return i; } finally { ++i; System.out.println("finally"); } }
按理說,應該返回2啊,可事實的返回結果為:
剛才解釋過,只有return才會把i的值放入到臨時的棧空間中,執行try中return i時,return將i的值,也就是1放入到棧空間中,finally執行時,i的值確實等於2,但是沒有更新到臨時的棧空間中,finally執行完後,返回棧空間中的值,也就是1.
如果在finally語句塊中return i呢?
public static int testFinally1() {
int i = 0;
try {
++i;
return i;
} catch (Exception e) {
++i;
return i;
} finally {
++i;
System.out.println("finally");
return i;
}
}
返回結果:
這是由於執行到finally中的return時,導致棧空間中的值被及時更新了,導致返回的結果是2。
但是這僅僅侷限於基本資料型別,簡單的理解為對於基本資料型別的變數,finally語句中的return會覆蓋try中的return。
那麼對於引用型別呢?注意我沒在finally中返回。
public static StringBuilder testFinally2() {
StringBuilder sb = new StringBuilder();
try {
sb.append("a");
return sb;
} catch (Exception e) {
sb.append("b");
return sb;
} finally {
System.out.println("finally");
sb.append("c");
}
}
輸出結果:
從這裡可以分析出,try中的return把sb這個變數引用而不是把“a"存入臨時的棧空間中了,那麼在finally中即使沒有更新棧空間的情況下,返回的值也是最新的值,即“ac”。
那麼,可以總結一下,對於基本資料型別的變數,臨時棧空間中直接存的就是具體的一個值。而對於引用變數,棧空間存放的是這個引用變數,而非具體的一個值。