java的世界千奇百怪。。。当我甩出如下代码段,不知阁下如何应对?

try(A a=new A()){
和a变量无关的业务代码块
}

没错,这就是“臭名昭著”的try-with-resource语法,乍一看让人不知所云,其实它和try-finally的下述代码等价

A a=new A()
try{
//业务代码块
}finally{
a.close();
}

本质上就是当使用 try-with-resources 语句块来处理实现了 AutoCloseable 接口的资源时,Java 编译器会在生成的字节码中进行特殊处理。编译器会自动在 try 块结束时插入 finally 块,并在 finally 块中调用 close() 方法来关闭资源。

try-with-resources语法

try-with-resources 语句是一个 Java 7 引入的语法结构,用于自动关闭实现了 AutoCloseable 或 Closeable 接口的资源。它的语法形式如下:

try (resource_declaration) {
// 使用资源的代码块
} catch (ExceptionType e) {
// 异常处理逻辑
}

在 try-with-resources 语句中,resource_declaration 部分用于声明和初始化一个或多个资源对象。这些资源对象必须实现 AutoCloseable 或 Closeable 接口。

在 try 代码块中,可以使用这些资源对象进行操作。当 try 代码块执行结束时,不论是正常结束还是发生异常,都会自动调用资源对象的 close() 方法来关闭资源。

如果同时声明了多个资源对象,可以使用分号 ; 分隔它们。

那么,它和try-finally语句有什么区别呢?

和try-finally的关系

很明显,try-with-resource语法相对于try-finally语法来说,隐式的调用了资源对象的close方法,语法更简洁,其次,让我们看看如下代码块:

@Test
public void testException(){ try{
throw new CustomException("代码块内的业务异常");
}finally {
throw new CustomException("finally中的资源释放异常");
}
}

运行上面的代码,你将会得到如下异常:

模仿上述代码,看看在try-with-resource语法中又会怎样

先创建一个类MyAutoClose

@Slf4j
public class MyAutoClose implements AutoCloseable {
@Override
public void close() throws Exception {
log.info("自动关闭");
throw new CustomException("close方法异常");
}
}

运行如下单元测试

@Test
public void testAutoClose() {
try (MyAutoClose autoClose = new MyAutoClose()) {
throw new CustomException("业务异常");
} catch (Exception e) {
log.error("", e);
}
}

得到如下异常

综合两种结果来看,可以看到同样的逻辑,业务和finally都是抛出了异常,但是抛出的异常却不一样:在try-finally语句块中,抛出的是finally中的异常,在try-with-resource语句块中,抛出的是业务的异常,而且异常中还携带了close方法关闭时抛出的异常信息。

谁好谁坏,自行体会。

try-with-resources的本质

再进一步细想一下,为啥两种方式逻辑基本一样,但是抛出的异常却不一样?

try-finally代码块很直观,try-with-resource代码块在编译成字节码文件的时候却被编译期“魔改”了,上文提到过

......Java 编译器会在生成的字节码中进行特殊处理。编译器会自动在 try 块结束时插入 finally 块,并在 finally 块中调用 close() 方法来关闭资源。

那只需要通过反编译看下class文件就可以了

再回想一下它原来长什么样子

@Test
public void testAutoClose() {
try (MyAutoClose autoClose = new MyAutoClose()) {
throw new CustomException("业务异常");
} catch (Exception e) {
log.error("", e);
}
}

亲妈都认不出来了。。。

我将反编译后的真正代码分成了四部分,并标记在了图上

  1. 外层异常try-catch块尝试捕获初始化资源异常
  2. 里层try-catch块尝试捕获业务执行异常
  3. 业务try-catch块捕获到异常,直接抛出
  4. finally块判定是否发生了业务异常:如果发生了业务异常,而且close方法执行也发生了异常,则将close方法发生的异常附加业务异常中;如果未发生业务异常,则直接执行close方法,这时候如果发生了异常,直接抛出的就是finally块中的异常了。

总结下,实际上是如下形式

try{
//初始化资源
try{
//业务代码执行
}catch(Exceptin e){
//捕获的业务异常,抛出业务异常
}finally{
//执行close方法,并判定在不同情况下的异常信息
}
}catch(Exception e){
//捕获的资源初始化异常
}

结论:使用try-with-resource很明显比使用try-finally块要更好一些,它能准确捕获业务异常;但是try-finally块也有不可替代的使用场景,比如资源类未实现AutoCloseable接口的时候

最后,欢迎关注我的博客原文:https://blog.kdyzm.cn/post/179

END.

java中的try-with-resource语法的更多相关文章

  1. java中根据key获取resource下properties资源文件中对应的参数

    properties资源文件是放在resource目录下的: 新建工具类: package com.demo.utils; import java.io.InputStream; import jav ...

  2. JAVA中abstract,interface,final,static语法

    转自:http://www.cnblogs.com/yueue/archive/2010/04/20/1715863.html 一,抽象类:abstract     1,只要有一个或一个以上抽象方法的 ...

  3. java中带参数的try(){}语法

    带资源的try语句(try-with-resource)的最简形式为: try(Resource res = xxx)//可指定多个资源 { work with res } try块退出时,会自动调用 ...

  4. java 中的异常处理

    一. 异常的概念和Java异常体系结构  异常是程序运行过程中出现的错误.本文主要讲授的是Java语言的异常处理.Java语言的异常处理框架,     是Java语言健壮性的一个重要体现. Java把 ...

  5. Java 中 JDBC 基础配置

    Java 中 JDBC 基础配置 <resource auth="Container" driverclassname="oracle.jdbc.driver.Or ...

  6. Java中的java.lang.Class API 详解

    且将新火试新茶,诗酒趁年华. 概述 Class是一个位于java.lang包下面的一个类,在Java中每个类实例都有对应的Class对象.类对象是由Java虚拟机(JVM)自动构造的. Class类的 ...

  7. Java中的方法和方法重载

    上次我们讲了Java中的一些基本的语法;今天我们就讲一点内容,来说说Java中的方法和方法重载以及需要注意的一些地方; 方法: Java的方法类似与其他语言的函数,是一段用来完成特定功能的代码片段, ...

  8. java中异常的抛出:throw throws

    java中异常的抛出:throw throws Java中的异常抛出 语法: public class ExceptionTest{ public void 方法名(参数列表) throws 异常列表 ...

  9. Java 中多态的实现(下)

    Java 中多态的另一个语法实现是重写.重载是通过静态分派实现的,重写则是通过动态分派实现的. 在学习动态分派之前,需要对虚拟机的知识有一个初步的了解. 虚拟机运行时数据区 运行 Java 程序时,虚 ...

  10. Java中的10颗语法糖

    语法糖(Syntactic Sugar):也称糖衣语法,指在计算机语言中添加的某种语法,这种语法对语言的功能没有影响,但是更方便程序员使用.通常来说,使用语法糖能够增加程序的可读性,减少程序代码出错的 ...

随机推荐

  1. 《小白WEB安全入门》02. 开发篇

    @ 目录 初识HTML潜在漏洞 初识CSS潜在漏洞 初识JS潜在漏洞 初识后端潜在漏洞 后端能做什么 后端种类 后端框架 潜在漏洞 本系列文章只叙述一些超级基础理论知识,极少有实践部分 本文涉及到的语 ...

  2. JS遍历Json串并获取Key和Value

    //data为json串 for (var key in data) { console.log(key); console.log(data[key]); }

  3. Codeforces 1257D - Yet Another Monster Killing Problem

    题意: 有\(n\)个怪物,每个怪物有攻击力\(a_i\)点:有\(m\)个英雄,每个英雄有攻击力\(p_i\)点,耐力\(s_{i}\)点. 怪物需要被依次杀死(按输入顺序). 每一天可以挑选一个英 ...

  4. Particles

    Smiling & Weeping ----我本想边走边爱,可你一个人就挡住了人山人海 牢骚:其实想明白了也就这么一回事,当时一直想dp,(# ̄- ̄#) 正解:其实题目说的明明白白,任选一个数 ...

  5. 使用 gopkg.in/yaml.v3 解析 YAML 数据

    YAML(YAML Ain't Markup Language)是一种人类可读的数据序列化格式,常用于配置文件和数据交换.在 Go 语言中,你可以使用 gopkg.in/yaml.v3 包来解析和生成 ...

  6. pta2023年9月7日 第五期

    5月23日   11月14日   有效期3年: 更新方式待定:  双方认证合作CCF编程培训师资认证(PTA)中国计算机学会https://pta.ccf.org.cn/中国科教工作者协会(原:中国青 ...

  7. ubuntu实时查看网速

    可以使用ifstat这个命令 安装 apt install ifstat   1 使用,直接打命令就行 ifstat

  8. C++算法之旅、09 力扣篇 | 常见面试笔试题(上)算法小白专用

    刷题的目的是为了更好的理解数据结构与算法,更好的理解一些封装起来的库函数是怎么实现的,而不是简简单单的为了刷题而刷题. 时间.空间复杂度 事后统计法 提前写好算法代码和编好测试数据,在计算机上跑,通过 ...

  9. ABC319 A-E 题解

    A 用 map <string, int> 将名字对应的值存下来即可. 赛时代码 B 按照题意暴力模拟,注意细节. 赛时代码 C 答辩题,卡了我半个小时. 枚举 \(1\sim 9\) 的 ...

  10. 20.2 OpenSSL 非对称RSA加解密算法

    RSA算法是一种非对称加密算法,由三位数学家Rivest.Shamir和Adleman共同发明,以他们三人的名字首字母命名.RSA算法的安全性基于大数分解问题,即对于一个非常大的合数,将其分解为两个质 ...