• java中的try-with-resource语法


    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中的资源释放异常");
        }
    }
    

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

    image-20231206102220734

    模仿上述代码,看看在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);
        }
    }
    

    得到如下异常

    image-20231206102818796

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

    谁好谁坏,自行体会。

    try-with-resources的本质

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

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

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

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

    image-20231206111141618

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

    @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.

  • 相关阅读:
    Javascript 使用技巧
    智能家居监控管理系统项目需求分析
    【微服务治理之监控APM】系统监控架构概述
    用于机器学习的 NumPy(ML)
    校园网页设计成品 学校班级网页制作模板 dreamweaver网页作业 简单网页课程成品 大学生静态HTML网页源码
    金属制品行业B2B交易管理系统:充分整合行业资源,助力企业开拓市场营销渠道
    spring配置文件第一行导致读取配置失败
    数据结构与算法训练:第二十弹
    盘点NFT史上令人难忘的跑路大王
    威纶通触摸屏的配方功能具体使用方法介绍(宏指令写入PLC)
  • 原文地址:https://www.cnblogs.com/kuangdaoyizhimei/p/17879164.html