日暮途远

日暮途远,涸辙难行;东隅已逝,桑榆非晚

Java7中的try-with-resources

前言

新出炉了阿里巴巴集团开发规约(正式版),在这里沾沾光,凑个热闹也来聊一聊Java编程中的一个小点,如果对大家在通向更优雅地写代码的路上有所帮助,那一定是极好的。

话说try-with-resources,这是JDK 7引入的新特性,现在JDK 9都快出来了,不过用的人还不是很多,可能和实际应用场景有限有关吧,感觉try-with-resources用来写写小程序还是不错的,比如双11某某活动需要开发根据运营对活动预算的调整推送配置,通常给你个excel,然后你再组织成代码能够识得的结构;亦或者是业务上有人群需求,运营给你个人群txt文件,然后你要组织成ODPS表结构需要的格式生成新的txt文件进行上传。诸如此类的需求还是不少的。

三姿

姿势一

在try-with-resources特性出来之前,你可能是这样做的:

真的就像懒婆娘的裹脚布,又臭又长。

姿势二

不过,自从JDK 7开始支持了try-with-resources之后,老板再也不用担心你的代码写得太丑啦,比如像这样:

额,看样子有点瘦了,但是还不够,而且有两个try catch,不够美观。

姿势三

再减减肥就是这样子:

总算看顺眼了,哈哈。

中场

Oracle提供的Java文档中有对这一特性的描述(点击这里查看)。英文一大堆,不过还是总结了几个需要注意的。

首先要区分try block和try-with-resources statement:

  • try block:指的是try花括号中的代码块,即资源声明之后的代码执行体,也就是操作资源;
  • try-with-resources statement:指的是try圆括号中的代码块,即资源声明。
  1. 该特性只适用于实现了java.lang.AutoCloseable接口的资源,确保在try-with-resources语句(原文表述为try-with-resources statement)结束时相关资源会被关闭。
  2. 在try block结束之后,无论是正常结束还是异常退出,都会执行资源的close方法以关闭资源;
  3. 在try-with-resources statement中允许声明多个资源(这也是resource为什么用复数s的原因),注意用半角分号隔开;
  4. 在try-with-resources statement结束时会依据资源的声明顺序反向调用close方法进行关闭。如上面姿势三中的代码,先后声明了br和bw,那么就会先后调用bw和br的close方法。

通篇其实分析了一个比较重要的点,就是当抛异常的时候,使用try-with-resources可以获得所有的异常,但是姿势一的使用方式则可能会丢掉重要异常:

当方法不捕获异常而直接往外抛的时候,如果br.readLine方法抛异常,进入finally后br.close方法也抛异常,两者抛的异常类型相同均为IOException,那么br.readLine抛的异常就被压制(suppressed-exceptions)了,因此上层只能拿到close抛的异常,这其实并没有什么用(当然通常来说比较好的做法是try块会先catch,打印堆栈日志,然后抛出自定义异常,这里不过是说明个问题);

而如果使用try-with-resources则可以避免这种情况的发生,如:

原文中的例子有问题,没有catch住打开资源时的FileNotFoundException异常,因此这里做了修改。这里实际的执行顺序是先获得文件读取资源,然后读取一行,然后关闭。当readLine方法和close方法均抛异常时,上层拿到的其实是关键的readLine方法抛出的异常,而close方法抛出的异常就被压制成为suppressed-exceptions,如果你需要拿到这些被压制的异常,可以调用Throwable.getSuppressed方法获取。

废话不多说,看下字节码(姿势三代码注释掉try block语句,只截取部分相关的,JDK版本1.7.0_79)是怎么说的:

在close时,如果抛出异常,那么55处会将抛出的异常写到本地变量,接下来会调用Throwable.addSuppressed将该异常暂存起来。完整的字节码太长,通过字节码也可以验证第4条的逆序close,感兴趣同学可以研究下字节码。

后语

本来想只写三姿的,结果居然可以写那么多废话。感谢你看到最后。

点赞

发表评论

电子邮件地址不会被公开。

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">