原文地址:http://blog.csdn.net/hengyunabc/article/details/18459463

这个所谓的try-with-resources,是个语法糖。实际上就是自动调用资源的close()函数。和Python里的with语句差不多。

例如:

  1. static String readFirstLineFromFile(String path) throws IOException {
  2. try (BufferedReader br = new BufferedReader(new FileReader(path))) {
  3. return br.readLine();
  4. }
  5. }

可以看到try语句多了个括号,而在括号里初始化了一个BufferedReader。

这种在try后面加个括号,再初始化对象的语法就叫try-with-resources。

实际上,相当于下面的代码(其实略有不同,下面会说明):

  1. static String readFirstLineFromFileWithFinallyBlock(String path) throws IOException {
  2. BufferedReader br = new BufferedReader(new FileReader(path));
  3. try {
  4. return br.readLine();
  5. } finally {
  6. if (br != null) br.close();
  7. }
  8. }

很容易可以猜想到,这是编绎器自动在try-with-resources后面增加了判断对象是否为null,如果不为null,则调用close()函数的的字节码。

只有实现了java.lang.AutoCloseable接口,或者java.io.Closable(实际上继随自java.lang.AutoCloseable)接口的对象,才会自动调用其close()函数。

有点不同的是Java.io.Closable要求一实现者保证close函数可以被重复调用。而AutoCloseable的close()函数则不要求是幂等的。具体可以参考Javadoc。

下面从编绎器生成的字节码来分析下,try-with-resources到底是怎样工作的:

  1. public class TryStudy implements AutoCloseable{
  2. static void test() throws Exception {
  3. try(TryStudy tryStudy = new TryStudy()){
  4. System.out.println(tryStudy);
  5. }
  6. }
  7. @Override
  8. public void close() throws Exception {
  9. }
  10. }

TryStudy实现了AutoCloseable接口,下面来看下test函数的字节码:

  1. static test()V throws java/lang/Exception
  2. TRYCATCHBLOCK L0 L1 L2
  3. TRYCATCHBLOCK L3 L4 L4
  4. L5
  5. LINENUMBER 21 L5
  6. ACONST_NULL
  7. ASTORE 0
  8. ACONST_NULL
  9. ASTORE 1
  10. L3
  11. NEW TryStudy
  12. DUP
  13. INVOKESPECIAL TryStudy.<init> ()V
  14. ASTORE 2
  15. L0
  16. LINENUMBER 22 L0
  17. GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
  18. ALOAD 2
  19. INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
  20. L1
  21. LINENUMBER 23 L1
  22. ALOAD 2
  23. IFNULL L6
  24. ALOAD 2
  25. INVOKEVIRTUAL TryStudy.close ()V
  26. GOTO L6
  27. L2
  28. FRAME FULL [java/lang/Throwable java/lang/Throwable TryStudy] [java/lang/Throwable]
  29. ASTORE 0
  30. ALOAD 2
  31. IFNULL L7
  32. ALOAD 2
  33. INVOKEVIRTUAL TryStudy.close ()V
  34. L7
  35. FRAME CHOP 1
  36. ALOAD 0
  37. ATHROW
  38. L4
  39. FRAME SAME1 java/lang/Throwable
  40. ASTORE 1
  41. ALOAD 0
  42. IFNONNULL L8
  43. ALOAD 1
  44. ASTORE 0
  45. GOTO L9
  46. L8
  47. FRAME SAME
  48. ALOAD 0
  49. ALOAD 1
  50. IF_ACMPEQ L9
  51. ALOAD 0
  52. ALOAD 1
  53. INVOKEVIRTUAL java/lang/Throwable.addSuppressed (Ljava/lang/Throwable;)V
  54. L9
  55. FRAME SAME
  56. ALOAD 0
  57. ATHROW
  58. L6
  59. LINENUMBER 24 L6
  60. FRAME CHOP 2
  61. RETURN
  62. LOCALVARIABLE tryStudy LTryStudy; L0 L7 2
  63. MAXSTACK = 2
  64. MAXLOCALS = 3

从字节码里可以看出,的确是有判断tryStudy对象是否为null,如果不是null,则调用close函数进行资源回收。

再仔细分析,可以发现有一个Throwable.addSuppressed的调用,那么这个调用是什么呢?

其实,上面的字节码大概是这个样子的(当然,不完全是这样的,因为汇编的各种灵活的跳转用Java是表达不出来的):

  1. static void test() throws Exception {
  2. TryStudy tryStudy = null;
  3. try{
  4. tryStudy = new TryStudy();
  5. System.out.println(tryStudy);
  6. }catch(Throwable suppressedException) {
  7. if (tryStudy != null) {
  8. try {
  9. tryStudy.close();
  10. }catch(Throwable e) {
  11. e.addSuppressed(suppressedException);
  12. throw e;
  13. }
  14. }
  15. throw suppressedException;
  16. }
  17. }

有点晕是吧,其实很简单。使用了try-with-resources语句之后,有可能会出现两个异常,一个是try块里的异常,一个是调用close函数里抛出的异常。

当然,平时我们写代码时,没有关注到。一般都是再抛出close函数里的异常,前面的异常被丢弃了。

如果在调用close函数时出现异常,那么前面的异常就被称为Suppressed Exceptions,因此Throwable还有个addSuppressed函数可以把它们保存起来,当用户捕捉到close里抛出的异常时,就可以调用Throwable.getSuppressed函数来取出close之前的异常了。

总结:

使用try-with-resources的语法可以实现资源的自动回收处理,大大提高了代码的便利性,和mutil catch一样,是个好东东。

用编绎器生成的字节码的角度来看,try-with-resources语法更加高效点。

java.io.Closable接口要求一实现者保证close函数可以被重复调用,而AutoCloseable的close()函数则不要求是幂等的。

参考:

http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

http://docs.oracle.com/javase/7/docs/api/java/lang/AutoCloseable.html

http://docs.oracle.com/javase/7/docs/api/java/io/Closeable.html

Java7里try-with-resources分析--转的更多相关文章

  1. 在WebApi项目里使用MiniProfiler并且分析 Entity Framework Core

    在WebApi项目里使用MiniProfiler并且分析 Entity Framework Core 一.安装配置MiniProfiler 在现有的ASP.NET Core MVC WebApi 项目 ...

  2. Java7里try-with-resources分析

    这个所谓的try-with-resources,是个语法糖.实际上就是自动调用资源的close()函数.和Python里的with语句差不多. 例如: [java] view plain copy   ...

  3. php里进程创建和分析

    pcntl_fork()函数创建一个子进程,这个子进程仅PID(进程号) 和PPID(父进程号)与其父进程不同成功时,在父进程执行线程内返回产生的子进程的PID,在子进程执行线程内返回0.失败时,在 ...

  4. spring-mvc里的 <mvc:resources> 及静态资源访问

    在进行Spring MVC的配置时,通常我们会配置一个dispatcher servlet用于处理对应的URL.配置如下: <servlet> <servlet-name>Sp ...

  5. springMvc里的mvc:resources与静态资源的访问

    在进行Spring MVC的配置时,通常我们会配置一个dispatcher servlet用于处理对应的URL.配置如下:   <servlet>   <servlet-name&g ...

  6. JQuery里的原型prototype分析

    在 JavaScript 中,每个函数对象都有一个默认的属性 prototype,称为函数对象的原型成员,这个属性指向一个对象,称为函数的原型对象,当我们每定义了一个函数的时候,JavaScript ...

  7. 单例模式中的多线程分析synchronized

    谈到单例模式,我们立马会想到饿汉式和懒汉式加载,所谓饿汉式就是在创建类时就创建好了实例,懒汉式在获取实例时才去创建实例,即延迟加载. 饿汉式: 1 package com.bijian.study; ...

  8. 转:XBMC源代码分析

    1:整体结构以及编译方法 XBMC(全称是XBOX Media Center)是一个开源的媒体中心软件.XBMC最初为Xbox而开发,可以运行在Linux.OSX.Windows.Android4.0 ...

  9. Hadoop源代码分析

    http://wenku.baidu.com/link?url=R-QoZXhc918qoO0BX6eXI9_uPU75whF62vFFUBIR-7c5XAYUVxDRX5Rs6QZR9hrBnUdM ...

随机推荐

  1. Vmware VM共享

    打开虚拟机,设置,选项点击共享文件夹 点击启用,将电脑windows的目录添加过来 进入终端即可以进入

  2. c# CacheHelper缓存帮助类

    一.开篇 主要功能:改善程序性能.服务器的响应速度,尤其是当数据的处理过程变得复杂以及访问量变大时,变得比较明显.有些数据并非时刻在发生变化,如果我们可以将一些变化不频繁的数据的最终计算结果(包括页面 ...

  3. 微信小程序中获取高度及设备的方法

    由于js中可以采用操纵dom的方法来获取页面元素的高度,可是在微信小程序中不能操纵dom,经过查找之后发现仅仅只有以下几个方法可以获取到高度 wx.getSystemInfoSync().window ...

  4. Java对象、Json、Xml转换工具Jackson使用

    在Java项目中將一个对象转换成一段Json格式的字符串是非常常见的,能够实现这种需求的工具包也比较多,例如Gson.JSON-lib.Jackson等等.本文主要介绍Jackson的使用,Jacks ...

  5. Unity 获取坐标函数 坐标转换函数

    获取世界坐标:transform.position 获取本地坐标:transform.localPosition 获取鼠标坐标:Input.mousePosition 获取手指触摸区域坐标:Input ...

  6. Java从入门到精通一步到位!

    Java作为近几年来非常火的编程语言,转行来做Java的人不计其数,但如今真正的人才仍然匮乏,所以学习Java一定要有一个系统的学习规划课程.阿里云大学帮您规划Java学习路线可以帮助您从一个小白成长 ...

  7. 一个helloword hibernate配置以及查询

    搭建一个Hibernate环境,开发步骤: 1. 下载源码 版本:hibernate-distribution-3.6.0.Final 2. 引入jar文件 hibernate3.jar核心  +   ...

  8. 在centos系统中增、删交换分区

    Swap介绍: Linux 将物理内存分为内存段,叫做页面.交换是指内存页面被复制到预先设定好的硬盘空间(叫做交换空间)的过程,目的是释放对于页面的内存.物理内存和交换空间的总大小是可用的虚拟内存的总 ...

  9. 浅谈 Qt 布局那些事

    Qt 布局那些事是本文介绍的内容,直接进入主题.GridLayout是一个非常强大的布局管理器,它可以实现很多复杂的布局,名字中暗示它将所有控件放置在类似网格的布局中.^__^GridLayout有两 ...

  10. 支持Openflow 1.3的wireshark插件安装教程

    目前为止,我们使用openflow wiki里提供的minient镜像里集成的wireshark只支持openflow1.0,我们通过wireshark上 菜单 help-->about wir ...