JDK1.7之后,引入了try-with-resources,使得关闭资源操作无需层层嵌套在finally中,代码简洁不少,本质是一个语法糖,能够使用try-with-resources关闭资源的类,必须实现AutoCloseable接口。

  1.7版本之前,传统的关闭资源操作如下:

public static void main(String[] args){

    FileInputStream fileInputStream = null;    try {        fileInputStream = new FileInputStream("file.txt");        fileInputStream.read();    } catch (IOException e) {        e.printStackTrace();    }finally {        try {            assert fileInputStream != null;            fileInputStream.close();        } catch (IOException e) {            e.printStackTrace();        }    }}

  可以看到,为了确保资源关闭正常,需要finall中再嵌入finally,try中打开资源越多,finall嵌套越深,可能会导致关闭资源的代码比业务代码还要多。

  但是使用了try-with-resources语法后,上面的例子可改写为:

try(FileInputStream fileInputStream1 = new FileInputStream("file.txt")){    fileInputStream1.read();} catch (IOException e) {    e.printStackTrace();}

  如何判读资源是否真的被关闭了呢,我们手写个Demo:

  实现AutoCloseable的资源类

class MyResource implements AutoCloseable{    public void open(){        System.out.println("resource is open!");    }    @Override    public void close() throws Exception {        System.out.println("resource is close!");    }}

  调用方:

public static void main(String[] args){    try(MyResource myResource = new MyResource()){        myResource.open();    } catch (Exception e) {        e.printStackTrace();    }
}

  输出如下,可以看到close方法被自动调用了,

resource is open!resource is close!

  底层原理是什么呢,看一下编译后的class文件:

try {        MyResource myResource = new MyResource();        Throwable var2 = null;        try {            myResource.open();        } catch (Throwable var12) {            var2 = var12;            throw var12;        } finally {            if (myResource != null) {                if (var2 != null) {                    try {                        myResource.close();                    } catch (Throwable var11) {                        var2.addSuppressed(var11);                    }                } else {                    myResource.close();                }            }        }    } catch (Exception var14) {        var14.printStackTrace();    }}

  很明显,编译器生成了finally代码块,并在其中调用了close 方法,同1.7之前的关闭资源操作的实现原理是相同的,但是可以看到,这里多调用了一个addSuppressed方法,这么做其实是为了处理异常屏蔽,什么是异常屏蔽,首先,我们先修改一下刚刚的Demo,使资源类在open和close方法中抛出异常,并且使用1.7之前的关闭资源的方法,资源类以及调用方代码修改如下:

public void open() throws IOException {    System.out.println("resource is open!");    throw new IOException("open() exception!");}@Overridepublic void close() throws Exception {    System.out.println("resource is close!");    throw new IOException("close()  exception!");}
public static void main(String[] args) throws Exception {    MyResource myResource = null;    try{        myResource = new MyResource();        myResource.open();    }finally {        try {            myResource.close();        } catch (Exception e) {            e.printStackTrace();        }    }
}

  控制台打印如下:

  open方法抛出的异常被自动忽略了,而异常信息丢失将导致程序调试困难,所以try-with-resources语法中加入了addSuppressed处理异常屏蔽,现在修改Demo为使用try-with-resource关闭资源,调用方代码如下:

public static void main(String[] args) throws Exception {    try(MyResource myResource = new MyResource()){        myResource.open();    }

  控制台打印如下

  

  异常信息中多了提示:close方法中抛出的异常被open方法中抛出的异常抑制了。

  其他问题:使用try-catch-resources,并不能完全保证资源被关闭,在javaBIO中,使用了大量的装饰器模式,调用装饰类的close方法时实际是在调用其中包裹的流的close方法,但是在调用包裹的流的close方法时,装饰类还做了一些其他的操作,如果这些操作出现异常,将导致包裹流的close方法被跳过,资源没有被正确关闭,正确的方式是在try中单独声明底层资源类以及装饰类,这样就可以保证,每个类的close方法都被调用。

eval a string with null_try-with-resources--JAVA成长之路相关推荐

  1. java date 加一天_Java 8中的时间JAVA成长之路

    Java 8新增了LocalDate和LocalTime接口,为什么要搞一套全新的处理日期和时间的API?因为旧的java.util.Date实在是太难用了. java.util.Date月份从0开始 ...

  2. 序列化与反序列化_序列化和反序列化JAVA成长之路

    一.序列化和反序列化的概念 把对象转换为字节序列的过程称为对象的序列化.把字节序列恢复为对象的过程称为对象的反序列化. 对象的序列化主要有两种用途: 1) 把对象的字节序列永久地保存到硬盘上,通常存放 ...

  3. transient关键字的作用_ArrayList Vector (transient关键字)--JAVA成长之路

    集合是Java中非常重要而且基础的内容,因为任何数据必不可少的就是数据的存储.集合的作用就是以一定的方式组织.存储数据.下面说说ArrayList,只捡干货聊. ArrayList特点 1.Array ...

  4. calendar类计算时间距离_日期时间--JAVA成长之路

    Java中为处理日期和时间提供了大量的API,确实有把一件简单的事情搞复杂的嫌疑,各种类:Date Time Timestamp Calendar...,但是如果能够看到时间处理的本质就可以轻松hol ...

  5. 掌握未来趋势的Java成长之路

    入门     javaSE基础         java基础语法             核心技能                  1.掌握Java开发环境基本配置                  ...

  6. java arraylist下标从几开始_ArrayList——JAVA成长之路

    1.1.ArrayList概述 1)ArrayList是可以动态增长和缩减的索引序列,它是基于数组实现的List类. 2)该类封装了一个动态再分配的Object[]数组,每一个类对象都有一个capac ...

  7. java的继承关系linkedlist_LinkedList——JAVA成长之路

    1.单向链表: element:用来存放元素 next:用来指向下一个节点元素 通过每个结点的指针指向下一个结点从而链接起来的结构,最后一个节点的next指向null. 2.单向循环链表:elemen ...

  8. 猿创征文|我的 Java 成长之路

    时隔许久,转眼间,我已成为一名大三的学生.在程序员这条路上磕磕碰碰,也总算有了一些成果.自己一直想要精通计算机的方方面面,但当自己继续向前,才发现这条路似乎是永无止境的.这时,选择 似乎才是最重要的✨ ...

  9. ArrayMap java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Object[]

    错误堆栈: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Object[]at android. ...

  10. 在拦截器中获取请求参数,[Ljava.lang.String; cannot be cast to java.lang.String报错

    Map<String,Object> parametersmap=invocation.getInvocationContext().getParameters();//获取请求参数    ...

最新文章

  1. common lisp 学习第一天 初步接触
  2. LeetCode 787. K 站中转内最便宜的航班(Dijkstra最短路径 + 优先队列)
  3. 作者:​覃海焕(1978-),女,博士,上海电机学院讲师。
  4. 调制的缺点_DML、EAM与MZI调制的比较
  5. linux添加硬盘永久挂载,linux新增硬盘如何挂载
  6. samba 设置文件的读写权限
  7. android上方导航条跳转页面,Native Navigation导航组件的使用说明
  8. 事务机制主要是利用undo、redo日志?
  9. 3种常用的Redis缓存读写策略
  10. 替换空格python实现
  11. 2018年10微型计算机接口技术,微机原理及接口技术
  12. 忘记卡巴斯基内置账户密码 / 取消卡巴斯基密码保护
  13. 读书笔记-人月神话10
  14. 微信公众号网页开发步骤
  15. 2021年系统架构设计师考试上午真题与答案
  16. Python: PS 图像特效 — 模糊玻璃
  17. 第二十章 幻读是什么,幻读有什么问题?
  18. 基于itchat获取微信好友头像
  19. C语言 | C语言深度解剖 ——章节2 符号
  20. DOTA全英雄装备介绍+物品简称[图文]

热门文章

  1. mysql.service failed because the control process exited with error code问题
  2. next.js 简单使用
  3. HTML5的新增功能
  4. C#基础篇三流程控制2
  5. Java数据类型和MySql数据类型对应表
  6. 两个链表生成相加链表
  7. 【收藏】vuejs学习笔记github地址
  8. 【收藏】在QGIS中导入GOOGLE、BING等地图和卫星影像(插件方式和XYZ方式)
  9. 【收藏】hdfs参数配置详解
  10. Linux创建文件系统的命令及xfs文件系统介绍