天天看點

優雅地關閉資源之try-with-resources

在Java程式設計中,如果打開了外部資源(檔案、資料庫連接配接、網絡連接配接等),我們必須在這些外部資源使用完畢之後,手動關閉他們。因為外部資源不由JVM管理,無法享用JVM的垃圾回收機制,如果我們不在程式設計時確定在正确的時機關閉外部資源,就會導緻外部資源洩露, 緊接着就會出現檔案被異常占用,資料庫連接配接過多導緻連接配接池溢出等諸多很嚴重的問題。

傳統關閉資源的方法如下:

注意:如果是節點流和處理流,可直接關閉處理流,因為io流使用了裝飾模式,是以關閉處理流時,會調用節點流的close()方法。

在JDK7以前,Java沒有自動關閉外部資源的文法特性,直到JDK7中新增了try-with-resource文法,才實作了這一功能。

那什麼是try-with-resource呢?簡而言之,當一個外部資源的句柄對象(比如FileInputStream對象)實作了AutoCloseable接口,那麼就可以将上面的闆式代碼簡化為如下形式:

将外部資源的句柄對象的建立放在try關鍵字後面的括号中,當這個try-catch代碼塊執行完畢後,Java會確定外部資源的close方法被調用。

之是以能這麼實作,是因為編譯器做了特殊處理。來看一下反編譯之後的代碼:

可以看到,反編譯之後的代碼就是傳統的關閉資源的方法。

通過反編譯的代碼,大家可能注意到代碼中有一處對異常的特殊處理:

這是try-with-resource文法涉及的另外一個知識點,叫做異常抑制。當對外部資源進行處理(例如讀或寫)時,如果遭遇了異常,且在随後的關閉外部資源過程中,又遭遇了異常,那麼你catch到的将會是對外部資源進行處理時遭遇的異常,關閉資源時遭遇的異常将被“抑制”但不是丢棄,通過異常的getSuppressed方法,可以提取出被抑制的異常。

這裡了解一點,就是try塊中抛出的異常,在finally也抛出異常時,就會丢失,是以通常在finally不抛異常,而是通過 addSuppressed()方法将異常抑制住。

1、當一個外部資源的句柄對象實作了AutoCloseable接口,JDK7中便可以利用try-with-resource文法更優雅的關閉資源,消除闆式代碼。

2、try-with-resource時,如果對外部資源的處理和對外部資源的關閉均遭遇了異常,“關閉異常”将被抑制,“處理異常”将被抛出,但“關閉異常”并沒有丢失,而是存放在“處理異常”的被抑制的異常清單中。

繼續閱讀