Effective Java【创建和销毁对象篇】 第9条 try-with-resources优先于try-finally

try-with-resources优先于try-finally

try-with-resources是jdk1.7引入的语法糖,使得关闭资源操作无需层层嵌套在finally。

Jav类库中包括许多调用close方法来手工关闭资源。例如:InputStream、OutputStream和java.sql.Connection。客户端经常会忽略资源的关闭,造成严重的性能后果,虽然这其中的许多资源都是用终结方法作为安全网,但是效果并不是很理想。

根据经验:try-finally语句是确保资源会被适时关闭的最佳方法,就算发生异常或者返回也一样。
请看下面的例子:

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();
        }
}

即便是try-finally语句正确的关闭了资源,如前两段代码所示,也存在不足,因为在try块和finally块的代码,都会抛出异常,例如,在firstLineOfFile方法中,如果底层的物理设备异常,那么调用readLine就会抛出异常,基于同样的原因,调用close也会出现异常,在这种情况下,第二个异常会完全抹去第一个异常。在异常堆栈轨迹中,完全没有关于第一个异常的记录,在现实中的系统的会导致调式变得非常复杂,因为通常需要看到第一个异常才能诊断出问题何在,虽然你可以通过编写代码来禁止第二个异常,但是太烦琐了。

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

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

使用try-with-resources不仅使得代码更加简洁易懂,也更容易判断错误原因,以firstLineOfFile方法为例,如果条用readLine和不可见close方法都抛出异常,后一个异常就会被禁止,以保留第一个异常,事实上,为了保留你想看到的那个异常,即便多个异常都可以禁用,这些被禁用的异常并不是简单的被抛弃,而是会被打印在堆栈轨迹中,并注明它们是被禁止的异常,通过编写调用getSuppressed方法还可以访问到它们。

在try-with-resources语句中还可以使用cath语句,就像在try-finally中一样使用,这样既可以处理异常,又不需要再多套一层代码。

下面举一个稍费了点心思的范例:这个firstLineOfFile方法没有抛出异常,但是如果它无法打开文件,或者无法从中读取,就会返回一个默认值。

static String firstLineOfFile(String path, String defaultVal) {
        try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
            return reader.readLine();
        } catch (IOException e) {
            return defaultVal;
        }
}

结论很明显:在处理必须关闭的资源时,始终要优先考虑使用try-with-resources,而不是try-finally。这样得到的代码将更简洁,清晰,产生的异常也更有价值,这些也是try-finally无法做到的。


参考文章:https://www.jianshu.com/p/8ae21436d850
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值