try-with-resources优于try-finally

        最近在看《Effective Java》看到第九点,try-with-resources 优先于try-finally。为了理解更加透彻,个人重新分析了一下,内容如下。

        在java开发中,一些网络链接或者是文件资源都需要程序员去手动调用close方法关闭,比如InputStream、OutputStream和java.sql.Connection。如果忘关了就可能造成严重的性能后果。而关闭的方法有很多种。比如finalizer、try-catch-finally、try-with-resources等等。

        finalizer机制可以关闭,但是其执行性不可预测,还有可能造成内存泄漏,所以一般不使用,虽然java9还提出了cleaner机制代替了finalizer机制,但是其执行依然不可预测,因此选择就落在了try-catch-finally和try-with-resources之间。

我们先看看try-catch-finally的在不同场景下的执行顺序。

1:代码没有异常

执行顺序:try执行完整->catch不执行->finally执行

2:代码有异常且catch进行捕获

执行顺序:try执行部分->跳转catch捕获处理->finally执行

3:代码有异常且catch不捕获:这种情况没有catch

执行顺序:try执行部分->finally执行

我们可以得出一个结论,不管有没有异常,如果有finally块,那么finally块代码一定是会被执行的。

我们来看看Effective Java的案例

static String firstLineOfFile(String path) throws IOException {
        BufferedReader reader = new BufferedReader(new FileReader(path));
        try {
            return reader.readLine();
        } finally {
            reader.close();
        }
    }

 关闭一个资源还好,但是如果再添加第二个资源,代码看起来就会一团糟了。

 static void copy(String src, String desc) throws IOException {
        InputStream in = new FileInputStream(src);
        try {
            OutputStream out = new FileOutputStream(desc);
            byte[] bytes = new byte[1024];
            int n;
            try {
                while ((n = in.read(bytes)) != -1) {
                    out.write(bytes, 0, n);
                }
            } finally {
                out.close();
            }
        } finally {
            in.close();
        }
    }

         如果再添加几个不同资源, 需要关闭的资源不仅种类多,而且数量也很多。代码就显得很臃肿,而且非常不优雅,还容易出现内存泄露的问题。

        当java7 引入try-with-resources语句时,所有这些问题一下子都全部解决了。要使用这个构造的资源,必须先实现AutoCloseable接口,其中包含了单个返回void的close方法。Java类库与第三方类库中的许多类和接口,现在都实现或扩展了AutoCloseable接口,如果编写了一个类,它代表的是必须被关闭的资源,那么这个类也应该实现AutoCloseable。

        以下就是使用try-with-resources的第一个范例。其中BufferedReader已经实现了AutoCloseable

    static String firstLineOfFile(String path) throws IOException {
        try (BufferedReader br = new BufferedReader(new FileReader(path))){
            return br.readLine();
        }
    }

        以下就是使用ry-with-resources的第二个范例。InputStream 和 OutputStream已经实现了AutoCloseable

static void copy(String src, String dst) throws IOException {
        try (InputStream inputStream = new FileInputStream(src); OutputStream outputStream = new FileOutputStream(dst)){
            byte[] buf = new byte[1024];
            while (inputStream.read(buf) >= 0){
                outputStream.write(buf,0,inputStream.read(buf));
            }
        }
    }

        使用try-with-resources不仅使代码变得更加简洁易懂,也更容易诊断,以firstLineOfFile方法为例,如果调用readLine和不可见的close方法都抛出异常,后一个异常就会被禁止,以保留第一个异常。但是我们实际上,这些异常我们都是想它们都打印出来,可以查看堆栈轨迹的。这个时候 我们可以通过getSUppressed方法还可以访问到它们,此方法也已经添加在Java7 的Throwable中了。

        经过上面例子,结论非常明显,在处理必须关闭的资源时,始终要优先考虑用try-with-resources,而不是try-finally,这样得到的代码将更加简洁,就能更轻松地正确编写代码,实践证明,这个用try-finally是不可能做到的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值