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

例如:

[java] view plain copy

 

  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。

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

[java] view plain copy

 

  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到底是怎样工作的:

[java] view plain copy

 

  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函数的字节码:

[java] view plain copy

 

  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是表达不出来的):

[java] view plain copy

 

  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()函数则不要求是幂等的。

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分析--转

    原文地址:http://blog.csdn.net/hengyunabc/article/details/18459463 这个所谓的try-with-resources,是个语法糖.实际上就是自动调 ...

  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. python MultiProcessing标准库使用Queue通信的注意要点

    今天原本想研究下MultiProcessing标准库下的进程间通信,根据 MultiProcessing官网 给的提示,有两种方法能够来实现进程间的通信,分别是pipe和queue.因为看queue顺 ...

  2. 《MySQL必知必会》读书笔记_2

    通配符:(尾空格可能会干扰通配符匹配) % 匹配任意字符 _ 匹配任意单个字符 正则表达式:REGEXP 用法就是替换掉LIKE的位置,后面配合正则表达式. 默认不区分大小写,如果区分的话添加关键字B ...

  3. eclipse调试的方法和技巧

    eclipse调试图标所代表的含义: Step into 单步进入-将进入执行的方法内部继续执行. Step over  单步前进-执行下一步. Step return – 单步退出-跳出正在执行的方 ...

  4. ajax调用servlet

    1.利用myecilpse建立一个web项目 2.导入需要的包: commons-beanutils.jar commons-collections-3.1.jar       commons-lan ...

  5. Jbpm工作流(一)

    了解一下什么是Jbpm及特点. jBPM,全称是Java Business Process Management,是一种基于J2EE的轻量级工作流管理系统.jBPM是公开源代码项目,它使用要遵循 Ap ...

  6. [ASP.NET MVC4高级编程] 学习记录(一)

    理论: 先有GUI在发展,当用户按下某个键,某个进程会监听到这个动作,这个进程就是控制器.这就是MVC模式. 后来有了事件驱动编程,响应动作的是按钮本身,而不是控制器. 再后来webForm中,事件驱 ...

  7. Hyper Text Transfer Protocol(超文本传输协议)

    HTTP简介 HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送 ...

  8. Java实现发送邮件(可配置)忘记密码,发送邮件

    学过Java基础的应该知道Java里有邮件这一块,不熟悉的话可以简单复习一下 本文章把发送邮件做为可配置可配置文件,这样方便以后维护 一.Maven依赖包 (发送邮件所依赖的jar包) <!-- ...

  9. TabBarController和其他view无法建立Relationship segue的原因

    拖拽怎么也没有那个出现,最后看sourcecode发现是那个那个viewcrontroler的XML 元素不是TabBarController.在Sourcecode里面改了一下,解决了这个问题. 总 ...

  10. Android Studio 插件开发详解一:入门练手

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/78112003 本文出自[赵彦军的博客] 一:概述 相信大家在使用Android S ...