點選「 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:防止找不到本篇文章,可以收藏點贊,方便翻閱尋找哦。
往期推薦