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 引入的语法结构,用于自动关闭实现了 AutoCloseableCloseable 接口的资源。它的语法形式如下:

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

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

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. .NET Evolve 数据库版本管理工具

    .NET Evolve数据库版本管理工具 1.简介 提到数据库版本管理,Java领域开发首先会想到大名鼎鼎的flyway.但是它不适用.NET领域,那么.NET领域也需要做数据库版本管理,该用什么工具 ...

  2. 《流畅的python》— 列表推导与生成器表达式

    列表推导是构建列表(list)的快捷方式,而生成器表达式则可以用来创建其他任何类型的序列.如果你的代码里并不经常使用它们,那么很可能你错过了许多写出可读性更好且更高效的代码的机会. 很多Python ...

  3. 快手Java一面11问(附参考答案)

    现在已经到了面试招聘比较火热的时候,后续会分享一些面试真题供大家复习参考.准备面试的过程中,一定要多看面经,多自测! 今天分享的是一位贵州大学的同学分享的快手一面面经. 快手一面主要会问一些基础问题, ...

  4. 银河麒麟SP2 auditd服务内存泄露问题

    这几天遇到基于海光服务器的银河麒麟V10 SP2版本操作系统出现内存无故增长问题. 排查发现auditd服务,占用了大量内存. 我的环境是银河麒麟V10 SP2 524,audit版本audit-3. ...

  5. oracle导入导出某个schema数据

    背景 公司之前部门拆分,但一些服务并没有拆分清楚.其中一个老服务,两个部门都在用,现在为了避免互相影响,决定克隆该服务.克隆就要克隆全套,当然也包括数据库,我们这个老服务,用的oracle,所以,就涉 ...

  6. Go学习笔记3

    九.错误处理 1.defer+recover机制处理异常错误 展示错误: 发现:程序中出现错误/恐慌以后,程序被中断,无法继续执行. 错误处理/捕获机制: 内置函数recover: 2.自定义错误 需 ...

  7. Java开发面试--nacos专区

    1. Nacos是什么? 请简要介绍Nacos是什么以及它的主要功能和用途. 答: 简介: Nacos是一个开源的.高性能.动态服务发现.配置和服务管理平台,通常用于微服务架构中.Nacos的名称来源 ...

  8. R3300L, Q7 ATV Android9固件

    R3300L, Q7 ATV Android9固件 固件来源 https://www.znds.com/tv-1239603-1-1.html 之前在恩山上发布过1080p安卓6固件 https:// ...

  9. IP协议的发展历程

    1. IP协议 1.1为什么需要IP协议 好像ip地址就像每个人的家门号一样家喻户晓,被大家默认用来作为寻址的门牌号,起初,设计IP地址也是为了寻找某台主机,但是作为世界上家喻户晓的IPv4,大家不应 ...

  10. SpringBootAdmin_监控

    监控的意义 监控服务状态是否宕机 监控服务运行指标(内存.虚拟机.线程.请求等) 监控日志 管理服务(服务下线) 监控的实施方式 大部分监控平台都是主动拉取监控信息,而不是被动地等待应用程序传递信息 ...