finally 語句裏還有大玄機,和我們想象的不一樣

今天我們來探討 Java 中的 finally 語句,通常用來關閉資源
但是有些情況下,在 finally 語句修改了值,可能對結果沒有什麼影響,我們來看看代碼,是怎麼回事。

我們看一段代碼,先在心裏想一個答案,然後繼續往下看

public class TryTest {

    private static int test() {
        int x = 1;
        try {
            System.out.println("A");
            return ++x;
        } catch (Exception e) {
            System.out.println("D");
        } finally {
            System.out.println("B");
            ++x;
        }
        System.out.println("C");
        return x;
    }

    public static void main(String[] args) {
        int result = test();
        System.out.println(result);
    }
}

答案是:
A
B
2

疑惑:爲什麼不是 AB3,又爲什麼不是ABC3?

帶着疑惑,我們通過 Debug 看下執行過程

(1)首先執行 try 中的語句,此時 x = 1

在這裏插入圖片描述
(2)然後執行 return ++x; 此時x = 1
在這裏插入圖片描述
(3)由於沒有拋出異常,此時不執行catch語句,繼續執行 finally 的語句
在這裏插入圖片描述
(4)繼續執行
在這裏插入圖片描述
(5)繼續執行,會發現,再次回到 try {…} 中的代碼,停留在 return ++x;
在這裏插入圖片描述
(6)再繼續執行,就已經返回了,但返回值是 2,不是剛剛的3
在這裏插入圖片描述
System.out.println(“B”); return x; 這兩句壓根就沒有執行,返回值也不是我們預期的3,WF ?

這是怎麼回事?
官方給出的解釋

如果 try 語句裏有 return,那麼代碼的行爲如下:

  1. 如果有返回值,就把返回值保存到局部變量中
  2. 執行 jsr 指令跳到 finally 語句裏執行
  3. 執行完 finally 語句後,返回之前保存在局部變量表裏的值。(雖然執行 ++x 後,x的值爲3,但是返回保存在局部變量中的x = 2)

根據以上的 debug 調試以及解釋說明就可以知道返回x爲什麼是2了。

當執行到 return ++x; jvm 再執行完 ++x 後會在局部變量表裏另外分配一個空間來保存當前的 x 值
注意,現在還沒有把返回值給 result,而是繼續執行 finally 語句里語句。等執行完後再把之前保存的值(是2,不是3)返回給 result

總結一下

finally 語句在 try 或 catch 中的 return 語句執行之後,返回之前執行。
且 finally 裏的修改語句不一定影響 try 或 catch 中 return 已經確定的值。
若 finally 裏也有 return 語句,則覆蓋 try 或 catch 中的 return語句直接返回。

另外,還有兩種情況,finally 語句不一定會執行的

1、 try 語句沒有被執行到,比如 在 try 語句執行之前就返回了,此時 finally 語句不會被執行的
2、try 塊中有 System.exit(); 這樣的語句,這個語句會終止 Java 虛擬機,連虛擬機都停了,當然 finally 語句也不會被執行了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章