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 述句:
然而在本例中,如果
readLine 和
close 方法同時丟出例外,則
readFirstLineFromFileWithFinallyBlock 方法最終丟出的是
finally 區塊中所產生的例外,而
try 區塊中產生的例外將會被抑制。相反地,在
readFirstLineFromFile 中,如果
try 區塊及
try-with-resources 述句中同時產生例外,則該方法最終丟出的將會是
try 區塊中所產生的例外,而不是
try-with-resources 述句中產生的例外。
也就是說,如果
readLine 和
close 方法同時丟出例外,則
readFirstLineFromFileWithFinallyBlock 方法會丟出由
close 方法所丟出的例外,並抑制
readLine 方法所丟出的例外;相反地
readFirstLineFromFile 方法會丟出由
readLine 方法所丟出的例外,並抑制
close 方法所丟出的例外。我們可以取得那些被抑制住的例外,細節請參考最後面的小節。
我們可以在
try-with-resources 述句中宣告一到多個資源。下例示範了如何從變數名為
zipFileName 的 ZIP 檔案中取得被壓縮的檔案名稱,並且建立一個包含這些檔案名稱的文字檔:
本例中
try-with-resources 述句宣告了兩個物件
ZipFile 及
BufferedWriter,並且用分號 ; 分開。當此區塊程式碼運作結束時,無論是正常結束或例外發生,
BufferedWriter 和
ZipFile 物件的
close 方法都會自動地依先後順序被呼叫。注意:呼叫所有資源
close 方法的順序和宣告它們的順序是相反的。
上面的程式片段在
finally 區段中的執行順序如下:
- rs.close();
- statement.close();
- conn.close();
- System.out.println("enter");
由此可知:
- 呼叫 close 方法的順序和宣告順序是相反的。
- 會先將所有資源都關閉後,才會正式進入 finally 區塊。
注意:
try-with-resources 述句可以擁有
catch 和
finally 區塊,如同原本的
try 述句一樣。在
try-with-resources 述句中,會先將所有被宣告的資源關閉後,才會進入
catch 和
finally 區塊。
被抑制的例外
在上例
writeToFileZipFileContents 中,如果
try 區塊中產生了一個例外的話 (例如
write 方法),那麼
try-with-resources 述句中的其他例外全都會被抑制下來 (
BufferedWriter 或
ZipFile 的
close 方法)。也就是說最後
writeToFileZipFileContents 方法丟出的是
try 區塊中的例外 (例如
write 方法)。如果我們想取得那些被抑制的例外的話,可以呼叫
Throwable.getSuppressed 方法。
實作了 AutoCloseable 和 Closeable 介面的類別
請參考
AutoCloseable 和
Closeable 介面的 JavaDoc,上面列出了所有已實作的類別。
Closeable 介面繼承自
AuyoCloseable 介面。它們兩個的不同處在於:
Closeable 介面的
close 方法會丟出
IOException 類型的例外,而
AutoCloseable 介面的
close 方法丟出的是
Exception 類型的例外。因此,
AutoCloseable 介面的子類別可以覆寫
close 方法的行為來丟出特定的例外,像是
IOException,或是根本就不丟出任何例外。