Java finally 的用法,看這一篇就夠了

本文獲得 baeldung team 的翻譯許可java

英文原文:www.baeldung.com/java-finall…git

1.概述

在本教程中,咱們將研究 Java 中的 finally 關鍵字的用法。 咱們將看到如何在錯誤處理中與 try / catch 塊一塊兒使用它。 儘管 finally 的目的是保證代碼被執行,可是咱們還將討論 JVM 不執行 finally 代碼的特殊狀況。github

咱們還將討論一些常見的陷阱,在這些陷阱中,finally 塊可能會產生意外的結果。ide

2.什麼是finally

try 關鍵字最後能夠定義 finally 代碼塊。 finally 塊中定義的代碼,老是在 try 和任何 catch 塊以後、方法完成以前運行。函數

正常狀況下,無論是否拋出或捕獲異常 finally 塊都會執行。編碼

2.1. 一個簡單的例子

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

2.2 不帶 catch 代碼塊的 finally

try {
    System.out.println("Inside try");
} finally {
    System.out.println("Inside finally");
}
複製代碼

結果操作系統

Inside try Insidefinally線程

2.3 finally 的使用場景

由於無論是否發生異常 finally 都會執行,所以咱們能夠在 finally 代碼塊中執行關閉鏈接、關閉文件和釋放線程的的操做。翻譯

3. finally 的執行時機

3.1 沒異常

當 try 代碼塊執行完成, finally 代碼塊就能夠執行,哪怕沒有發生異常。

try {
    System.out.println("Inside try");
} finally {
    System.out.println("Inside finally");
}
複製代碼

Inside try Inside finally

3.2 有異常可是沒處理器

哪怕 異常沒有被 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

3.3 有異常處理器

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

3.4 try 代碼塊中帶返回值

即便 try 代碼塊中返回,也不能阻止 finally 代碼塊的執行。

try {
    System.out.println("Inside try");
    return "from try";
} finally {
    System.out.println("Inside finally");
}
複製代碼

JVM 會在返回到調用函數前執行 finally 代碼塊。

Inside try Inside finally

3.5 在 catch 代碼塊中返回

在 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

4 啥時候 finally 不會被執行

儘管一般編寫 finally 代碼塊是爲了這段代碼必定被執行到,可是也有一些特殊狀況會致使 JVM 不會執行 finally 代碼塊。

若是操做系統中斷了咱們的程序,那麼finally 代碼塊可能就不能被執行。也有不少其餘相似的行爲致使 finally代碼塊不被執行。

4.1 調用 System.exit 函數

try {
    System.out.println("Inside try");
    System.exit(1);
} finally {
    System.out.println("Inside finally");
}
複製代碼

結果

Inside try

4.2 調用 halt 函數

try {
    System.out.println("Inside try");
    Runtime.getRuntime().halt(1);
} finally {
    System.out.println("Inside finally");
}
複製代碼

Inside try

4.3 守護線程

若是守護線程剛開始執行到 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

4.4 try 代碼塊中無限循環

try {
    System.out.println("Inside try");
    while (true) {
    }
} finally {
    System.out.println("Inside finally");
}
複製代碼

Try 代碼塊出現無限循環,且不出現異常,finally 也將永遠得不到執行。

5. 常見陷阱

咱們在使用 finally 關鍵字時會遇到不少陷阱。

有一些很差的編碼方式,如在 finally 代碼塊中存在返回值或者扔出異常。

5.1 忽視異常

finally 代碼塊包含返回語句,沒有處理未捕獲的異常。

try {
    System.out.println("Inside try");
    throw new RuntimeException();
} finally {
    System.out.println("Inside finally");
    return "from finally";
}
複製代碼

此時,try 代碼塊中的 RuntimeException 會被忽略,函數返回 "from finally"字符串。

5.2 覆蓋其餘返回語句

若是 finally 代碼塊中存在返回語句,則 try 和 catch 代碼塊若是存在返回語句就會被忽略。

try {
    System.out.println("Inside try");
    return "from try";
} finally {
    System.out.println("Inside finally");
    return "from finally";
}
複製代碼

此段代碼老是返回 「from finally」 。

5.3 改變 throw 或 return 行爲

若是再 finally 代碼塊中扔出異常,則 try 和 catch 中的異常扔出或者返回語句都將被忽略。

try {
    System.out.println("Inside try");
    return "from try";
} finally {
    throw new RuntimeException();
}
複製代碼

這段代碼永遠都不會有返回值,老是會拋出 RuntimeException。

6. 結論

本文咱們討論了 Java 的 finally 關鍵字的用法。而後討論了 finally 執行和不執行 finally 代碼塊的狀況。

最後給出了開發中關於 finally 常見的使用的陷阱。

須要本文代碼,能夠去GitHub 配套 項目中下載。


7. 思考題

譯者補充: 結合第 4 部分的示例,你們能夠思考一下,其餘方式可讓 finally 得不到執行嗎? 歡迎你們在下方評論探討。


若是你以爲本文對你有幫助,歡迎點贊、轉發、評論,你的支持是我創做的最大動力。

相關文章
相關標籤/搜索