首先回忆一下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); }