首先回憶一下jdk1.7以前,咱們要經過流讀取文件時,代碼要怎樣寫?java
假設本地文件系統d盤下有一個in.txt文件,代碼以下:編碼
FileInputStream in = null; try { in = new FileInputStream("d:/in.txt"); } catch(Exception e) { System.out.println(e.getMessage()); throw new RuntimeException("try塊中產生了異常",e); } finally { if (in != null) in.close(); }
此時試想一個問題:若是try塊中new FileInputStream拋出了異常,在finally塊中調用close方法時也拋出了異常,那麼最終拋給上層的到底是哪一個異常?spa
答案是:拋給上層的是close方法產生的異常。code
可是很明顯,咱們但願的是把catch塊中捕獲的異常進行處理後,繼續向上拋出,可結果卻由於close方法產生異常而丟失了咱們預期的異常。對象
針對此問題,解決方案是:調用in.close()時再次使用try-catch塊包裹,代碼以下:接口
FileInputStream in = null; try { in = new FileInputStream("d:/in.txt"); } catch(Exception e) { System.out.println(e.getMessage()); throw new RuntimeException("try塊中產生了異常",e); } finally { if (in != null) try { in.close(); }catch(IOException e) { e.printStackTrace(); } }
至此,問題已經獲得完美解決。可是,每次處理IO問題時都要編碼重複且複雜的代碼是否是很繁瑣?因而,jdk1.7推出了叫作try-with-resources的語法糖。則上面的代碼能夠改下以下:get
/** * try-with-resource語法糖 */ try (FileInputStream in = new FileInputStream("d:/in.txt")) { // do something } catch(Exception e) { System.out.println("message:"+e.getMessage()); throw new RuntimeException("try塊中產生了異常",e); }
try()中的類型必須實現AutoCloseable接口(jdk1.7開始引入了此接口,做爲Closeable接口的父接口)。it
此結構的執行順序爲:io
執行try快中語句class
調用try()中的全部對象的close()方法
若是try塊產生異常,則執行catch中的邏輯
若是存在finally塊,則執行其邏輯
另外,還須要注意的是:
若是try塊產生了異常,則會忽略close產生的異常(若是真的產生異常的話);不然纔會拋出close產生的異常(若是真的產生異常的話)。
所以,try-with-resources語法糖等價於如下寫法:
// 此處的try至關於 // try (FileInputStream in = new FileInputStream("d:/in.txt")) try { InputStream in = null; /** * 如下try-catch能夠理解爲語法糖自動生成的代碼 */ try { in = new FileInputStream("d:/in.txt"); // do something in.close(); } catch (IOException e) { if (in != null) try { in.close(); } catch (IOException ee) { if (e != ee) e.addSuppressed(ee); } throw e; } } catch (IOException e) { System.out.println(e.getMessage()); throw new RuntimeException("try塊中產生了異常", e); }