當前位置: 妍妍網 > 碼農

Java 的 finally 程式碼塊的程式碼一定會執行嗎?

2024-05-09碼農

點選「 IT碼徒 」, 關註,置頂 公眾號

每日技術幹貨,第一時間送達!

1

前言


對於很多初學者而言,會想當然地認為 「finally 程式碼塊一定會被執行」,因此我們可以看下面這個案例:

public classDemo {
publicstaticvoidmain(String[] args) {
try {
BufferedReader br = new BufferedReader(new ileReader("file.txt"));
System.out.println(br.readLine());
br.close();
} catch (IOException e) {
// 省略一些程式碼
} finally {
System.out.println("Exiting the program");
}
}
}

問題是:該段程式碼 finally 的程式碼塊一定會被執行嗎?為什麽?

2

問題分析



通常實際編碼時,捕獲異常後會記錄日誌或者將異常丟擲等,此時 finally 程式碼塊一般肯定會被執行到。

那麽如何才能不執行finally呢?

於是我們想到,如果讓虛擬機器結束,問題不就解決了嗎? (就是這麽暴力)

因此填充程式碼:

public classDemo {
publicstaticvoidmain(String[] args) {
try {
BufferedReader br = new BufferedReader(new ileReader("file.txt"));
System.out.println(br.readLine());
br.close();
} catch (IOException e) {
System.exit(2);
} finally {
System.out.println("Exiting the program");
}
}
}

如果捕獲到IO異常,則會執行虛擬機器結束指令,則不會執行finally程式碼塊。

System#exit 的源碼如下:

publicstaticvoidexit(int status){
Runtime.getRuntime().exit(status);
}

透過註釋我們可以了解到,當 status 為非0時,表示異常結束。

底層呼叫到 Runtime#exit:

publicvoidexit(int status){
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkExit(status);
}
Shutdown.exit(status);
}

3

延伸



同樣的問題,請看下面程式碼片段:

public classDemo {
publicstaticvoidmain(String[] args) {
// 一些程式碼
try {
BufferedReader br = new BufferedReader(new ileReader("file.txt"));
System.out.println(br.readLine());
br.close();
} catch (IOException e) {
System.exit(2);
} finally {
System.out.println("Exiting the program");
}
}
}

問題是: 如果try程式碼塊部份發生IO異常,是否一定不會執行到 finally 程式碼塊呢?

what? 上面不是說不會執行嗎?

我們再仔細看上面給出的 Runtime#exit 源碼,可以發現,如果 SecurityManager 不為 null ,則會進行安全檢查。

publicvoidexit(int status){
// 如果有securityManager , 則呼叫 checkExit函式
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkExit(status);
}
// 檢查透過後結束
Shutdown.exit(status);
}

安全檢查透過才會執行 Shutdown#exit 執行最終的虛擬機器結束。

因此如果我們可以修改 SecurityManager 如果檢查結束時丟擲異常,那麽在執行System.exit(2) 時就會發生異常,最終依然會執行到 finally程式碼塊。

public classDemo {
publicstaticvoidmain(String[] args) {
// 修改 SecurityManager
System.setSecurityManager(new SecurityManager() {
@Override
publicvoidcheckExit(int status)
{
thrownew SecurityException("不允許結束");
}
});
try {
BufferedReader br = new BufferedReader(new ileReader("file.txt"));
System.out.println(br.readLine());
br.close();
} catch (IOException e) {
System.exit(2);
} finally {
System.out.println("Exiting the program");
}
}
}

4

總結



學習時一定要抱著不滿足的心態,這樣才能有機會學的更加深入,理解地更好。

END

PS:防止找不到本篇文章,可以收藏點贊,方便翻閱尋找哦。

往期推薦