1. 程式人生 > >【JAVA】當finally遇上return

【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”。

那麼,可以總結一下,對於基本資料型別的變數,臨時棧空間中直接存的就是具體的一個值。而對於引用變數,棧空間存放的是這個引用變數,而非具體的一個值。