Java_优雅的关闭资源连接_try-with-resource

背景

在Java中,如果打开了外部资源(文件、数据库连接、网络连接等),因为外部资源不由JVM管理,无法享用JVM的垃圾回收机制,我们必须在这些外部资源使用完毕后,手动关闭它们。如果我们不在编程时确保在正确的时机关闭外部资源,就会导致外部资源泄露,紧接着就会出现文件被异常占用,数据库连接过多导致连接池溢出等诸多很严重的问题

传统关闭方式

为了确保外部资源一定要被关闭,通常关闭代码被写入finally代码块中,我们还要考虑到关闭资源时可能抛出的异常,并且抛出异常时我们还要确保其他资源可以正常关闭,于是变有了下面的经典代码

public class TryWithResourceDemo {
    public static void main(String[] args) {
        BufferedInputStream bin = null;
        BufferedOutputStream bout = null;
        try {
            bin = new BufferedInputStream(new FileInputStream(new File("test.txt")));
            bout = new BufferedOutputStream(new FileOutputStream(new File("out.txt")));
            int b;
            while ((b = bin.read()) != -1) {
                bout.write(b);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bin != null) {
                try {
                    bin.close();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (bout != null) {
                        try {
                            bout.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}

这简直就是噩梦……关闭资源比业务代码都长,这大佬肯定忍不了,所以就有了try-with-resource来简化大量的样板式代码

public class TryWithResourceDemo {
    public static void main(String[] args) {
        try (BufferedInputStream bin = new BufferedInputStream(new FileInputStream(new File("test.txt")));
             BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(new File("out.txt")))) {
            int b;
            while ((b = bin.read()) != -1) {
                bout.write(b);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

wow~这就是try-with-resource,我们把需要用到的资源连接放在try语句后面的小括号里,这个语法可以确保当try语句执行完毕后会把小括号里面的连接全部关闭,是不是很酷。但这并不是什么新的机制,是编译器帮我们做了工作,和foreach一样,这也是一个语法糖,编译器会生成和我们手写的一样的try-catch-finally语句(手头没有可以反编译的工具,所以没办法看代码),我们可以使用链式语句来让编译器生成尽量少的语句块,但前提是我们要足够了解不同对象内部对close方法的实现

使用try-with-resource的前提
  • 资源必须实现AutoClosable接口
  • JDK1.7及以上的版本
注意

在使用try-with-resource的过程中,一定需要了解资源的close方法内部的实现逻辑,否则还是可能会导致资源消耗

    private static void compress(String input, String output) throws IOException {
        try(
                FileInputStream fin = new FileInputStream(input);
                GZIPOutputStream out = new GZIPOutputStream(new FileOutputStream(output))
        ) {
            byte[] buffer = new byte[4096];
            int nread = 0;
            while ((nread = fin.read(buffer)) != -1) {
                out.write(buffer, 0, nread);
            }
        }
    }

这是GZIPOutputStream类的close方法,大家可以看到在关闭out之前还有一个finish操作,如果这个操作发生了异常会导致out没有被关闭

    public void close() throws IOException {
        if (!closed) {
            finish();
            if (usesDefaultDeflater)
                def.end();
            out.close();
            closed = true;
        }
    }
  • 正确姿势
    private static void compress(String input, String output) throws IOException {
        try (
                FileInputStream fin = new FileInputStream(input);
                FileOutputStream fout = new FileOutputStream(output);
                GZIPOutputStream out = new GZIPOutputStream(fout)
        ) {
            byte[] buffer = new byte[4096];
            int nread = 0;
            while ((nread = fin.read(buffer)) != -1) {
                out.write(buffer, 0, nread);
            }
        }
    }

单独声明资源,这样编译器会为每一个对象都生成try-catch-finally语句块来确保每一个资源都会被关闭
官网的详细介绍(中文)try-with-resources

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值