Java try()語句實現try-with-resources異常管理機制操作
Java try()語句實現try-with-resources異常管理機制
java7 新增特性,對於try語句塊中使用到的資源,不再需要手動關閉,在語句塊結束後,會自動關閉,類似於python的with..as的用法。
利用這個特性,需要實現AutoCloseable接口,隻有一個close方法,實現關閉資源的操作。
public interface AutoCloseable{ public void close() throws Exception; }
所有的流,都實現瞭這個接口,可以在try()中進行實例化。自定義的類隻要實現瞭這個接口,也可以使用這個特性。
不使用try-with-resources時,使用的資源要在finally中進行釋放
package stream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; public class TestStream { public static void main(String[] args) { File f = new File("d:/test.txt"); FileInputStream fis = null; try { fis = new FileInputStream(f); } catch (IOException e) { e.printStackTrace(); } finally { // 在finally 裡關閉流 if (null != fis) try { fis.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
使用try-with-resources時
形式為try(),括號內可以包含多個語句。
package stream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; public class TestStream { public static void main(String[] args) { File f = new File("d:/lol.txt"); //把流定義在try()裡,try,catch或者finally結束的時候,會自動關閉 try (FileInputStream fis = new FileInputStream(f)) { byte[] all = new byte[(int) f.length()]; fis.read(all); for (byte b : all) { System.out.println(b); } } catch (IOException e) { e.printStackTrace(); } } }
自定義AutoCloseable實現
在TestAutoCloseable的close方法中打印信息
package test; public class TestAutoCloseable implements AutoCloseable{ public TestAutoCloseable() { System.out.println("class TestAutoCloceable"); } public void close() { System.out.println("function close() executed"); } }
測試代碼
package test; public class TestFeature { public static void main(String[] args) { // TODO Auto-generated method stub try(TestAutoCloseable testAutoCloseable = new TestAutoCloseable()){ } } }
結果close方法被調用
try-with-resources語句優雅的關閉資源
在Java編程過程中,如果打開瞭外部資源(文件、數據庫連接、網絡連接等),我們必須在這些外部資源使用完畢後,手動關閉它們。
因為外部資源不由JVM管理,無法享用JVM的垃圾回收機制,如果我們不在編程時確保在正確的時機關閉外部資源,就會導致外部資源泄露,緊接著就會出現文件被異常占用,數據庫連接過多導致連接池溢出等諸多很嚴重的問題。
在java1.7以前,我們關閉資源的方式如下
public class CloseTest { public static void main(String[] args){ FileInputStream fileInputStream = null; try { fileInputStream = new FileInputStream("file.txt"); fileInputStream.read(); } catch (IOException e) { e.printStackTrace(); }finally { if (fileInputStream != null){ try { fileInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
為瞭確保外部資源一定要被關閉,通常關閉代碼被寫入finally代碼塊中,關閉資源時可能拋出的異常,於是經典代碼就誕生瞭。
但是,在java1.7版本之後,新增加瞭一個語法糖,就是try-with-resources語句,
我們先直接上一個demo,方便理解
public class CloseTest { public static void main(String[] args) { try (FileInputStream fileInputStream1 = new FileInputStream("file1.txt"); FileInputStream fileInputStream2 = new FileInputStream("file2.txt")) { fileInputStream1.read(); fileInputStream2.read(); } catch (IOException e) { e.printStackTrace(); } } }
將外部資源的句柄對象的創建放在try關鍵字後面的括號中,當這個try-catch代碼塊執行完畢後,Java會確保外部資源的close方法被調用。多個語句使用分號斷開。
反編譯之後我們可以看見
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); } }
通過反編譯的代碼,大傢可能註意到代碼中有一處對異常的特殊處理:
var2.addSuppressed(var11);
這是try-with-resource語法涉及的另外一個知識點,叫做異常抑制。當對外部資源進行處理(例如讀或寫)時,如果遭遇瞭異常,且在隨後的關閉外部資源過程中,又遭遇瞭異常,那麼你catch到的將會是對外部資源進行處理時遭遇的異常,關閉資源時遭遇的異常將被“抑制”但不是丟棄,通過異常的getSuppressed方法,可以提取出被抑制的異常。
源碼裡面有解釋
/** * Returns an array containing all of the exceptions that were * suppressed, typically by the {@code try}-with-resources * statement, in order to deliver this exception. * * If no exceptions were suppressed or {@linkplain * #Throwable(String, Throwable, boolean, boolean) suppression is * disabled}, an empty array is returned. This method is * thread-safe. Writes to the returned array do not affect future * calls to this method. * * @return an array containing all of the exceptions that were * suppressed to deliver this exception. * @since 1.7 */ public final synchronized Throwable[] getSuppressed() { if (suppressedExceptions == SUPPRESSED_SENTINEL || suppressedExceptions == null) return EMPTY_THROWABLE_ARRAY; else return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY); }
總結一下吧
因為不管什麼情況下(異常或者非異常)資源都必須關閉,在jdk1.6之前,應該把close()放在finally塊中,以確保資源的正確釋放。如果使用jdk1.7以上的版本,推薦使用try-with-resources語句。
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- java面試try-with-resources問題解答
- Java中IO流解析及代碼實例詳解
- 圖文詳解Java中的字節輸入與輸出流
- 使用ByteArrayOutputStream寫入字符串方式
- Java inputstream和outputstream使用詳解