原文地址: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. POJ 3185 DFS

    好像可以用高斯消元??? 但是用搜索写 这题就很水了... // by SiriusRen #include <bitset> #include <cstdio> using ...

  2. 算法入门经典-第六章 例题6-21 SystemDependencies

    题意:软件组件之间会有依赖关系,比如你下一个Codeblocks你也得顺带着把编译器给下上.你的任务是模拟安装和卸载软件组件的过程.有以下五种指令,如果指令为“END”则退出程序:若为以下四种指令,则 ...

  3. Ubuntu 14.04安装Skype

    Skype 4.3版本在14.04 LTS工作正常.安装步骤: $ sudo apt-get remove skype skype-bin:i386 skype:i386 $ sudo apt-get ...

  4. Java基础——增强for循环

    java1.5版本引入了一个增强for循环,基本原理和for循环类似. 语法声明:for(表达式:条件表达式) 举例:for (String str : set) 解释:set代表set集合,str代 ...

  5. 如何创建一个asp页面

    Active Server Pages(ASP)文件是以 .asp 为扩展名的文本文件,这个文本文件可以包括下列部分的任意组合: 文本 HTML 标记 ASP 脚本命令 创建 .asp 文件非常容易. ...

  6. solarwinds之配置系统管理(System manager)

    配置windows的 1.  打开System Manager   2.  点击new新加一个接口   3.  选择要监控的资源   4.  确认好自己要监控的资源后如下   5.  这里以监控内存使 ...

  7. POJ 1995 Raising Modulo Numbers 【快速幂取模】

    题目链接:http://poj.org/problem?id=1995 解题思路:用整数快速幂算法算出每一个 Ai^Bi,然后依次相加取模即可. #include<stdio.h> lon ...

  8. RocketMQ学习笔记(10)----RocketMQ的Producer 事务消息使用

    1. 事务消息原理图 RocketMQ除了支持普通消息,顺序消息之外,还支持了事务消息. 1. 什么是分布式事务? 分布式事务就是指事务的参与者.支持事务的服务器.资源服务器以及事务管理器分别位于不同 ...

  9. 【AnjularJS系列4 】 — 单个页面加载多个ng-App

    第四篇,插播, 单个页面加载多个ng-App 在写范例的时候发现的问题 一个页面有多个ng-app,angular只会处理第一个ng-app 需要加载两个ng-app,需要进行手动加载: angula ...

  10. linux yum安装找不到源

    1先说问题: 服务器装麒麟系统后安装gis地图(其实就是部署一套地图服务),因为是内网,所以所有需要的包都放在一个iso文件中了,需要用mount命令去加载之,然后配置*.repo文件(源文件配置), ...