try-with-resource仅仅是一个语法糖吗?

良心公众号

关注不迷路

01

管理外部资源的痛点

熟悉Java的小伙伴都知道,得益于JVM的垃圾回收机制,我们无需投入大量的精力在内存空间的管理上,但对于诸如文件、数据库连接、网络连接等外部资源的使用,就没那么幸运了。

由于外部资源无法由JVM进行管理,因此,必须在申请和使用相关的外部资源之后,必须进行显式的释放,否则,就会导致外部资源的泄漏,出现资源占用异常、连接池溢出等等一系列严重的问题。

为了避免上述问题的发生,在JDK1.7之前,我们只能通过一些列并不优雅的显式的外部资源释放逻辑,搭配以冗长的异常处理嵌套,来手动实现外部资源的释放。以文件资源为例,我们可以看一段JDK1.7之前文件资源使用的代码示例。

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;


public class FileTest {
    public static void main(String[] args) {
        FileOutputStream outputStream = null;
        try {
            System.out.println("start ^_^");
            outputStream = new FileOutputStream(new File("c:/test_files/test.txt"));
            outputStream.write("hello, test man!".getBytes());
            System.out.println("write file success ^o^");
        } catch (IOException e) {
            System.out.println("there is no such file!");
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    System.out.println("close file error!");
                }
            }
        }
    }
}

简单运行之后,将会得到如下结果:

"JavaPath\Java\jdk-11.0.7\bin\java.exe" "-javaagent:IDEAPath\IntelliJ IDEA 2020.1.2\lib\idea_rt.jar=7242:IDEAPath\IntelliJ IDEA 2020.1.2\bin" -Dfile.encoding=UTF-8 -classpath C:\test\out\production\test FileTest
start ^_^
write file success ^o^


Process finished with exit code 0

虽然达到了向test.txt写入hello, test man!的目的,但代码看起来实在是不够优雅!

02

优雅地关闭外部资源

为了解决这种尴尬的场面,JDK1.7增加了try-with-resource的语法,从JDK层面对外部的资源管理进行了支持,从而可以优雅地关闭外部资源。这听起来像一个语法糖,事实上,它确实是一个语法糖!但这个语法糖的内部实现,对我们日常的开发以及问题排查,是很有借鉴意义的。接下来,就让我们看看try-with-resource的具体实现吧。

依旧以文件资源为例,我们采用try-with-resource的方式对上文中的程序加以改写。得到如下所示的程序:

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;


public class FileTest {
    public static void main(String[] args) {
        try (FileOutputStream outputStream = new FileOutputStream(new File("c:/test_files/test.txt"));) {
            System.out.println("start ^_^");
            outputStream.write("hello, test man!".getBytes());
            System.out.println("write file success ^o^");
        } catch (IOException e) {
            System.out.println("there is no such file!");
        }
    }
}


相比之下,使用try-with-resource的方式,代码显得清爽多了,省去了编写finally代码块,代码的可读性更高了。那么try-with-resource到底是怎么做到维护外部资源的呢?

上文提到了,它是JDK1.7新增的一个语法糖,既然是语法糖,那就并没有什么新的东西,只是JDK代你做了一些处理,从而优化了编码体验。具体细节我们可以看一下使用try-with-resource方式实现FileTest对应的class文件:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//


import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;


public class FileTest {
    public FileTest() {
    }


    public static void main(String[] args) {
        try {
            FileOutputStream outputStream = new FileOutputStream(new File("c:/test_files/test.txt"));


            try {
                System.out.println("start ^_^");
                outputStream.write("hello, test man!".getBytes());
                System.out.println("write file success ^o^");
            } catch (Throwable var5) {
                try {
                    outputStream.close();
                } catch (Throwable var4) {
                    var5.addSuppressed(var4);
                }


                throw var5;
            }


            outputStream.close();
        } catch (IOException var6) {
            System.out.println("there is no such file!");
        }


    }
}

03

可靠的异常抑制

看完之后是不是忍不住想起那句话:哪有什么岁月静好,不过是有人替你负重前行……感慨之余,这里面还有个细节,值得我们学习。在异常处理中的第26行代码内容为var5.addSuppressed(var4);这行代码使得抛出的外层异常,能够包含内层异常的相关信息。这就是所谓的异常抑制

异常抑制对于排查问题,尤其是像本文的示例这样有异常嵌套的程序,具有十分重要的意义。因为它不会将内层异常的信息吞没,使得排查代码的线索丢失,反之,它将保留程序的完整异常栈,使排查问题显得有迹可循。这一点可以很好地利用到工作中复杂的异常处理场景中,从而提升代码的可维护性

今天关于try-with-resource的总结就到这里了。

欢迎大家一起讨论技术,共同成长!


学习 | 工作 | 分享

????长按关注“有理想的菜鸡

只有你想不到,没有你学不到

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值