优先使用try-with-resources-第二章创建和销毁对象-Effective Java学习笔记08

文章内容来源于Joshua Bloch - Effective Java (3rd) - 2018.chm一书

第二章

创建和注销对象

Item 9优先使用try-with-resources相比于try-finally

Java库包含许多必须通过调用close方法手动关闭的资源。示例包括InputStream、OutputStream和java.sql.Connection连接. 关闭资源常常被客户忽略,这会带来可怕的性能后果。虽然这些资源中有许多将终结器用作安全网,但Finalizer的情况并不好

历史上,try finally语句是保证资源正确关闭的最佳方式,即使在遇到异常或返回时也是如此:

// try-finally - No longer the best way to close resources!
static String firstLineOfFile(String path) throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(path));
    try {
        return br.readLine();
    } finally {
        br.close();
    }
} 

这看起来没问题,但添加第二个资源时情况会变糟:

// try-finally is ugly when used with more than one resource!
static void copy(String src, String dst) throws IOException {
    InputStream in = new FileInputStream(src);
    try {
        OutputStream out = new FileOutputStream(dst);
        try {
            byte[] buf = new byte[BUFFER_SIZE];
            int n;
            while ((n = in.read(buf)) >= 0)
                out.write(buf, 0, n);
        } finally {
            out.close();
        }
    } finally {
        in.close();
    }
} 

这可能很难让人相信,但即使是优秀的程序员在大多数情况下也犯了这个错误。
事实上,在2007年,Java库中close方法的使用有三分之二是错误的。
即使使用try finally语句关闭资源的正确代码(如前两个代码示例所示)也有一个微妙的缺陷。try块和finally块中的代码都能够抛出异常

当Java7引入try with resources语句时,这些问题都解决了

要使用此构造,资源必须实现AutoCloseable接口,该接口由单个空返回的close方法组成。Java库和第三方库中的许多类和接口现在实现或扩展了AutoCloseable
如果您编写了一个表示必须关闭的资源的类,那么您的类就应该实现AutoCloseable。

下面是使用try with resources的第一个示例:

// try-with-resources - the the best way to close resources!
static String firstLineOfFile(String path) throws IOException {
    try (BufferedReader br = new BufferedReader(
           new FileReader(path))) {
       return br.readLine();
    }
} 

下面是第二个示例如何使用try with resources:

// try-with-resources on multiple resources - short and sweet
static void copy(String src, String dst) throws IOException {
    try (InputStream   in = new FileInputStream(src);
         OutputStream out = new FileOutputStream(dst)) {
        byte[] buf = new byte[BUFFER_SIZE];
        int n;
        while ((n = in.read(buf)) >= 0)
            out.write(buf, 0, n);
    }
} 

try-with-resources版本不仅比try-finally更短、可读性更高,而且提供了更好的报错诊断
举例firstLineOfFile 方法
如果一个异常既被readLine调用还被(不可见的)close抛出,那么后面的异常将被抑制,而只有前者抛出
实际上,可以抑制多个异常,以便保留您实际希望看到的异常。这些被抑制的异常不仅仅被丢弃;它们被打印在堆栈跟踪中,并带有一个表示它们被抑制的符号
你可以使用getSuppressed方法以编程方式访问它们

可以将catch子句放在try with resources语句上,就像放在常规try finally语句上一样。这使您能够处理异常,而不会因为一层嵌套而影响代码
作为一个有点不自然的示例,以下是我们的firstlineofile方法的一个版本,它不会抛出异常,但如果无法打开文件或从中读取文件,则会返回一个默认值:

// try-with-resources with a catch clause
static String firstLineOfFile(String path, String defaultVal) {
    try (BufferedReader br = new BufferedReader(
           new FileReader(path))) {
        return br.readLine();
    } catch (IOException e) {
        return defaultVal;
    }
} 

教训很清楚:在处理必须关闭的资源时,总是优先使用try with resources,而不是try finally。生成的代码更短、更清晰,它生成的异常也更有用。try with resources语句使得使用必须关闭的资源编写正确的代码变得容易,而使用try finally实际上是做不到这些

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值