咱們知道,在Java編程過程當中,若是打開了外部資源(文件、數據庫鏈接、網絡鏈接等),咱們必須在這些外部資源使用完畢後,手動關閉它們。由於外部資源不禁JVM管理,沒法享用JVM的垃圾回收機制,若是咱們不在編程時確保在正確的時機關閉外部資源,就會致使外部資源泄露,緊接着就會出現文件被異常佔用,數據庫鏈接過多致使鏈接池溢出等諸多很嚴重的問題。數據庫
爲了確保外部資源必定要被關閉,一般關閉代碼被寫入finally代碼塊中,固然咱們還必須注意到關閉資源時可能拋出的異常,因而變有了下面的經典代碼:編程
public static void main(String[] args) { FileInputStream inputStream = null; try { inputStream = new FileInputStream(new File("test")); System.out.println(inputStream.read()); } catch (IOException e) { throw new RuntimeException(e.getMessage(), e); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { throw new RuntimeException(e.getMessage(), e); } } } }
熟悉其餘語言的朋友可能會開始吐槽了,在C++中,咱們能夠把關閉資源的代碼放在析構函數中,在C#中,咱們有using代碼塊。這些語法都有一個共同的特性,讓外部資源的關閉行爲與外部資源的句柄對象的生命週期關聯,當外部資源的句柄對象生命週期終結時(例如句柄對象已出做用域),外部資源的關閉行爲將被自動調用。這樣不只更加符合面向對象的編程理念(將關閉外部資源的行爲內聚在外部資源的句柄對象中),也讓代碼更加簡潔易懂。怎麼到了Java這裏,就找不到自動關閉外部資源的語法特性了呢。網絡
確實,在JDK7之前,Java沒有自動關閉外部資源的語法特性,直到JDK7中新增了try-with-resource語法,才實現了這一功能。函數
那什麼是try-with-resource呢?簡而言之,當一個外部資源的句柄對象(好比FileInputStream對象)實現了AutoCloseable接口,那麼就能夠將上面的板式代碼簡化爲以下形式:spa
public static void main(String[] args) { try (FileInputStream inputStream = new FileInputStream(new File("test"))) { System.out.println(inputStream.read()); } catch (IOException e) { throw new RuntimeException(e.getMessage(), e); } }
將外部資源的句柄對象的建立放在try關鍵字後面的括號中,當這個try-catch代碼塊執行完畢後,Java會確保外部資源的close方法被調用。代碼是否是瞬間簡潔許多!code
try-with-resource並非JVM虛擬機的新增功能,只是JDK實現了一個語法糖,當你將上面代碼反編譯後會發現,其實對JVM虛擬機而言,它看到的依然是以前的寫法:對象
public static void main(String[] args) { try { FileInputStream inputStream = new FileInputStream(new File("test")); Throwable var2 = null; try { System.out.println(inputStream.read()); } catch (Throwable var12) { var2 = var12; throw var12; } finally { if (inputStream != null) { if (var2 != null) { try { inputStream.close(); } catch (Throwable var11) { var2.addSuppressed(var11); } } else { inputStream.close(); } } } } catch (IOException var14) { throw new RuntimeException(var14.getMessage(), var14); } }
經過反編譯的代碼,你們可能注意到代碼中有一處對異常的特殊處理:blog
var2.addSuppressed(var11);
這是try-with-resource語法涉及的另一個知識點,叫作異常抑制。當對外部資源進行處理(例如讀或寫)時,若是遭遇了異常,且在隨後的關閉外部資源過程當中,又遭遇了異常,那麼你catch到的將會是對外部資源進行處理時遭遇的異常,關閉資源時遭遇的異常將被「抑制」但不是丟棄,經過異常的getSuppressed方法,能夠提取出被抑制的異常。接口
一、當一個外部資源的句柄對象實現了AutoCloseable接口,JDK7中即可以利用try-with-resource語法更優雅的關閉資源,消除板式代碼。生命週期
二、try-with-resource時,若是對外部資源的處理和對外部資源的關閉均遭遇了異常,「關閉異常」將被抑制,「處理異常」將被拋出,但「關閉異常」並無丟失,而是存放在「處理異常」的被抑制的異常列表中。