try-finally 和 try-catch-finally 語句

try...catch...finally 語句將異常處理與清理程式碼結合在一起。finally 塊包含將在所有情況下執行的程式碼。這使它們適用於資源管理和其他型別的清理。

嘗試,終於

這是一個更簡單(try...finally)形式的例子:

try {
    doSomething();  
} finally {
    cleanUp();
}

try...finally 的行為如下:

  • 執行 try 塊中的程式碼。
  • 如果 try 塊沒有丟擲異常:
    • 執行 finally 塊中的程式碼。
    • 如果 finally 塊丟擲異常,則傳播該異常。
    • 否則,控制傳遞到 try...finally 之後的下一個語句。
  • 如果 try 塊中丟擲了異常:
    • 執行 finally 塊中的程式碼。
    • 如果 finally 塊丟擲異常,則傳播該異常。
    • 否則,原始異常繼續傳播。

finally 塊中的程式碼將始終執行。 (唯一的例外是如果呼叫 System.exit(int),或者如果 JVM 發生混亂。)因此,finally 塊是始終需要執行的正確位置程式碼; 例如關閉檔案和其他資源或釋放鎖。

try-catch-終於

我們的第二個例子展示了 catchfinally 如何一起使用。它還說明清理資源並不簡單。

// This code snippet writes the first line of a file to a string
String result = null;
Reader reader = null;
try {
    reader = new BufferedReader(new FileReader(fileName));
    result = reader.readLine();
} catch (IOException ex) {
    Logger.getLogger.warn("Unexpected IO error", ex);  // logging the exception
} finally {
    if (reader != null) {
        try {
            reader.close();
        } catch (IOException ex) {
            // ignore / discard this exception
        }
    }
}

在這個例子中,try...catch...finally 的一整套(假設的)行為太複雜了,不能在這裡描述。簡單的版本是 finally 塊中的程式碼將始終執行。

從資源管理的角度來看這個:

  • 我們在 try 塊之前宣告資源(即 reader 變數),以便它將在 finally 塊的範圍內。
  • 通過放置 new FileReader(...)catch 能夠處理開啟檔案時丟擲的任何 IOError 異常。
  • 我們需要在 finally 塊中使用 reader.close(),因為我們無法在 try 塊或 catch 塊中攔截一些異常路徑。
  • 但是,由於在初始化 reader 之前可能會丟擲異常,我們還需要一個明確的 null 測試。
  • 最後,reader.close() 呼叫可能(假設)丟擲異常。我們並不關心這一點,但如果我們不在源頭捕獲異常,我們需要在呼叫堆疊中進一步處理它。

Version >= Java SE 7

Java 7 及更高版本提供了另一種 try-with-resources 語法 ,可顯著簡化資源清理。