本文獲得 baeldung team 的翻譯許可java
英文原文:www.baeldung.com/java-finall…git
在本教程中,咱們將研究 Java 中的 finally 關鍵字的用法。 咱們將看到如何在錯誤處理中與 try / catch 塊一塊兒使用它。 儘管 finally 的目的是保證代碼被執行,可是咱們還將討論 JVM 不執行 finally 代碼的特殊狀況。github
咱們還將討論一些常見的陷阱,在這些陷阱中,finally 塊可能會產生意外的結果。ide
try 關鍵字最後能夠定義 finally 代碼塊。 finally 塊中定義的代碼,老是在 try 和任何 catch 塊以後、方法完成以前運行。函數
正常狀況下,無論是否拋出或捕獲異常 finally 塊都會執行。編碼
try {
System.out.println("The count is " + Integer.parseInt(count));
} catch (NumberFormatException e) {
System.out.println("No count");
} finally {
System.out.println("In finally");
}
複製代碼
在這個示例中,無論參數的值是多少,JVM 都執行 finally 塊並輸出「 In finally」。spa
try {
System.out.println("Inside try");
} finally {
System.out.println("Inside finally");
}
複製代碼
結果操作系統
Inside
try Inside
finally線程
由於無論是否發生異常 finally 都會執行,所以咱們能夠在 finally 代碼塊中執行關閉鏈接、關閉文件和釋放線程的的操做。翻譯
當 try 代碼塊執行完成, finally 代碼塊就能夠執行,哪怕沒有發生異常。
try {
System.out.println("Inside try");
} finally {
System.out.println("Inside finally");
}
複製代碼
Inside try Inside finally
哪怕 異常沒有被 catch , finally 代碼塊依然會執行。
try {
System.out.println("Inside try");
throw new Exception();
} finally {
System.out.println("Inside finally");
}
複製代碼
即便出現未被處理的異常,JVM 依然會執行 finally 代碼塊的代碼。
Inside try Inside finally Exception in thread "main" java.lang.Exception
try 代碼塊發生異常, 被 catch 捕捉, finally 依然會執行。
try {
System.out.println("Inside try");
throw new Exception();
} catch (Exception e) {
System.out.println("Inside catch");
} finally {
System.out.println("Inside finally");
}
複製代碼
Inside try Inside catch Inside finally
即便 try 代碼塊中返回,也不能阻止 finally 代碼塊的執行。
try {
System.out.println("Inside try");
return "from try";
} finally {
System.out.println("Inside finally");
}
複製代碼
JVM 會在返回到調用函數前執行 finally 代碼塊。
Inside try Inside finally
在 catch 代碼塊中添加返回語句,finally 代碼依然會執行。
try {
System.out.println("Inside try");
throw new Exception();
} catch (Exception e) {
System.out.println("Inside catch");
return "from catch";
} finally {
System.out.println("Inside finally");
}
複製代碼
結果
Inside try Inside catch Inside finally
儘管一般編寫 finally 代碼塊是爲了這段代碼必定被執行到,可是也有一些特殊狀況會致使 JVM 不會執行 finally 代碼塊。
若是操做系統中斷了咱們的程序,那麼finally 代碼塊可能就不能被執行。也有不少其餘相似的行爲致使 finally代碼塊不被執行。
try {
System.out.println("Inside try");
System.exit(1);
} finally {
System.out.println("Inside finally");
}
複製代碼
結果
Inside try
try {
System.out.println("Inside try");
Runtime.getRuntime().halt(1);
} finally {
System.out.println("Inside finally");
}
複製代碼
Inside try
若是守護線程剛開始執行到 finally 代碼塊,此時沒有任何其餘非守護線程,那麼虛擬機將退出,此時 JVM 不會等待守護線程的 finally 代碼塊執行完成。
Runnable runnable = () -> {
try {
System.out.println("Inside try");
} finally {
try {
Thread.sleep(1000);
System.out.println("Inside finally");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Thread regular = new Thread(runnable);
Thread daemon = new Thread(runnable);
daemon.setDaemon(true);
regular.start();
Thread.sleep(300);
daemon.start();
複製代碼
輸出
Inside try Inside try Inside finally
try {
System.out.println("Inside try");
while (true) {
}
} finally {
System.out.println("Inside finally");
}
複製代碼
Try 代碼塊出現無限循環,且不出現異常,finally 也將永遠得不到執行。
咱們在使用 finally 關鍵字時會遇到不少陷阱。
有一些很差的編碼方式,如在 finally 代碼塊中存在返回值或者扔出異常。
finally 代碼塊包含返回語句,沒有處理未捕獲的異常。
try {
System.out.println("Inside try");
throw new RuntimeException();
} finally {
System.out.println("Inside finally");
return "from finally";
}
複製代碼
此時,try 代碼塊中的 RuntimeException 會被忽略,函數返回 "from finally"字符串。
若是 finally 代碼塊中存在返回語句,則 try 和 catch 代碼塊若是存在返回語句就會被忽略。
try {
System.out.println("Inside try");
return "from try";
} finally {
System.out.println("Inside finally");
return "from finally";
}
複製代碼
此段代碼老是返回 「from finally」 。
若是再 finally 代碼塊中扔出異常,則 try 和 catch 中的異常扔出或者返回語句都將被忽略。
try {
System.out.println("Inside try");
return "from try";
} finally {
throw new RuntimeException();
}
複製代碼
這段代碼永遠都不會有返回值,老是會拋出 RuntimeException。
本文咱們討論了 Java 的 finally 關鍵字的用法。而後討論了 finally 執行和不執行 finally 代碼塊的狀況。
最後給出了開發中關於 finally 常見的使用的陷阱。
須要本文代碼,能夠去GitHub 配套 項目中下載。
譯者補充: 結合第 4 部分的示例,你們能夠思考一下,其餘方式可讓 finally 得不到執行嗎? 歡迎你們在下方評論探討。
若是你以爲本文對你有幫助,歡迎點贊、轉發、評論,你的支持是我創做的最大動力。