try-with-resources 述句可以讓我們在 try 述句中宣告一到數項資源。當我們說某個物件是一項資源時,意味著該物件實作了 java.lang.AutoCloseable 或是它的子介面 java.lang.Closeable,並且當程式不再使用它們時,我們需要將其關閉。try 新增的述句確保每項資源在區段結束時都會被關閉。

早期我們都必須要自行處理資源的關閉,但現在我們可以藉助此一述句來簡化程式。下例會從檔案中讀取第一行,它使用 BufferedReader 物件來讀檔。BufferedReader 是一項資源,並且當程式不再使用它時,我們必須將其關閉:

本例中我們用新的 try 語法來宣告了一個 BufferedReader 資源,此語句必須接在 try 關鍵字之後,並且用圓括號 () 包起來。BufferedReader 在 Java SE 7 及其後版本裡,已實作了 java.lang.AutoCloseable 介面。因為 BufferedReader 實體是在 try-with-resource 述句中所宣告的,所以它將會被自動關閉;無論是 try 區塊正常結束,或是被突然中斷 (像是 BufferedReader.readLine 丟出 IOException)。

早期 Java 版本中,我們可以用 finally 區塊來確保資源被正確關閉 (不管 try 區塊是正常結束或是突然結束)。下例使用 finally 來替代 try-with-resources 述句:

然而在本例中,如果 readLineclose 方法同時丟出例外,則 readFirstLineFromFileWithFinallyBlock 方法最終丟出的是 finally 區塊中所產生的例外,而 try 區塊中產生的例外將會被抑制。相反地,在 readFirstLineFromFile 中,如果 try 區塊及 try-with-resources 述句中同時產生例外,則該方法最終丟出的將會是 try 區塊中所產生的例外,而不是 try-with-resources 述句中產生的例外。

也就是說,如果 readLineclose 方法同時丟出例外,則 readFirstLineFromFileWithFinallyBlock 方法會丟出由 close 方法所丟出的例外,並抑制 readLine 方法所丟出的例外;相反地 readFirstLineFromFile 方法會丟出由 readLine 方法所丟出的例外,並抑制 close 方法所丟出的例外。我們可以取得那些被抑制住的例外,細節請參考最後面的小節。

我們可以在 try-with-resources 述句中宣告一到多個資源。下例示範了如何從變數名為 zipFileName 的 ZIP 檔案中取得被壓縮的檔案名稱,並且建立一個包含這些檔案名稱的文字檔:

本例中 try-with-resources 述句宣告了兩個物件 ZipFileBufferedWriter,並且用分號 ; 分開。當此區塊程式碼運作結束時,無論是正常結束或例外發生,BufferedWriterZipFile 物件的 close 方法都會自動地依先後順序被呼叫。注意:呼叫所有資源 close 方法的順序和宣告它們的順序是相反的。

上面的程式片段在 finally 區段中的執行順序如下:

  1. rs.close();
  2. statement.close();
  3. conn.close();
  4. System.out.println("enter");
由此可知:
  1. 呼叫 close 方法的順序和宣告順序是相反的。
  2. 會先將所有資源都關閉後,才會正式進入 finally 區塊。
注意:try-with-resources 述句可以擁有 catchfinally 區塊,如同原本的 try 述句一樣。在 try-with-resources 述句中,會先將所有被宣告的資源關閉後,才會進入 catchfinally 區塊。

被抑制的例外

在上例 writeToFileZipFileContents 中,如果 try 區塊中產生了一個例外的話 (例如 write 方法),那麼 try-with-resources 述句中的其他例外全都會被抑制下來 (BufferedWriterZipFileclose 方法)。也就是說最後 writeToFileZipFileContents 方法丟出的是 try 區塊中的例外 (例如 write 方法)。如果我們想取得那些被抑制的例外的話,可以呼叫 Throwable.getSuppressed 方法。

實作了 AutoCloseableCloseable 介面的類別

請參考 AutoCloseableCloseable 介面的 JavaDoc,上面列出了所有已實作的類別。Closeable 介面繼承自 AuyoCloseable 介面。它們兩個的不同處在於:Closeable 介面的 close 方法會丟出 IOException 類型的例外,而 AutoCloseable 介面的 close 方法丟出的是 Exception 類型的例外。因此,AutoCloseable 介面的子類別可以覆寫 close 方法的行為來丟出特定的例外,像是 IOException,或是根本就不丟出任何例外。