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. 10款Visual Studio实用插件

    前言 俗话说的好工欲善其事必先利其器,安装一些Visual Studio实用插件对自己日常的开发和工作效率能够大大的提升,避免996从选一款好的IDE实用插件开始.以下是我认为比较实用的Visual ...

  2. vue2和vue3使用echarts时无数据,怎么显示暂无数据图片或文字

    一开始也经历了用v-if和v-show,v-show的话echarts还会留出暂无数据图片的位置,导致echarts变形,v-if在加载和不加载切换时,dom会获取不到:后来也是在网上找的方法,时间有 ...

  3. 两个例子带你入门 Disruptor

    Disruptor 是英国外汇交易公司 LMAX 开发的一个高性能队列.很多知名开源项目里,比如 canal .log4j2. storm 都是用了 Disruptor 以提升系统性能 . 这篇文章, ...

  4. Vue 脚手架编程

    1.1 初始化脚手架 1.1.1 说明 Vue 脚手架是 Vue 官方提供的标准化开发工具(开发平台) 最新的版本是 4.x 文档 1.1.2 具体步骤 第一步(仅第一次执行):全局安装 @vue/c ...

  5. Solution Set -「ARC 124」

    「ARC 124A」LR Constraints Link. 我们可以把 \(1\sim n\) 个盒子里能放的球的编号集合全部求出来.然后就直接来. 注意题目已经给出了 \(k\) 个球的位置,所以 ...

  6. C++ RAII在HotSpot VM中的重要应用

    RAII(Resource Acquisition Is Initialization),也称为"资源获取就是初始化",是C++语言的一种管理资源.避免泄漏的惯用法.C++标准保证 ...

  7. Python网络编程——操作系统基础、网络通信原理、.网络通信实现、DNS域名解析、 网络通信流程

    文章目录 一.操作系统基础 二.网络通信原理 2.1 互联网的本质就是一系列的网络协议 2.2 osi七层协议 2.3 tcp/ip五层模型讲解 2.3.1 物理层 2.3.2 数据链路层 2.3.3 ...

  8. Python基础合集

    入门介绍 01.python由来与发展介绍 02.WEB项目开发流程 第一篇 markdown编辑器 01.markdown基本语法 02.Typora简介与安装 03.Windows上gitee+T ...

  9. linux常见命令(四)

    用于查看日期和时间的相关命令 cal date hwclock cal:显示日历信息 命令语音:cal [选项] [[[日]月]年] 选项 选项含义 -j 显示出给定月中的每一天是一年总的第几天(从1 ...

  10. SharedPreferences-PreferenceUtils

    SharedPreferences   easy use import android.content.Context; import android.content.SharedPreference ...