try-with-resources语法糖

try-catch-finally 与 try-with-resources

传统的 try-catch-finally 结构虽然能够实现资源的正确关闭,但代码冗长。
try-with-resources(自动资源管理) 语法糖,在声明或者使用使用完资源后,不再需要手动编写关闭资源的代码,实现自动调用close()方法关闭,并使代码更加清晰明了。
多资源关闭时,其中一个资源时抛出了异常,则该异常将不会影响其他资源正常关闭。

但这同样带来了一些问题,笔记先阐述使用方式与基本概念,在阐述一些隐藏的问题。

  • 异常抑制
  • 自动关闭了一些不该关闭的流
  • 此语法糖的Class必须实现AutoCloseable接口
    (AutoCloseable接口只有一个close方法来实现自动关闭)
// 代码简洁 自动关闭
// try-with-resources
try (InputStream inputStream = new FileInputStream("file.txt")) {
    // 使用inputStream进行操作
} catch (IOException e) {
    // 异常处理
}

// 传统的try-catch-finally
InputStream inputStream = null;
try {
    inputStream = new FileInputStream("file.txt");
    // 使用inputStream进行操作
} catch (IOException e) {
    // 异常处理
} finally {
    if (inputStream != null) {
        try {
            inputStream.close();
        } catch (IOException e) {
            // 关闭资源时的异常处理
        }
    }
}


// 多资源关闭回收
try (InputStream input = new FileInputStream("input.txt");
     OutputStream output = new FileOutputStream("output.txt")) {
    // 使用input和output进行操作
} catch (IOException e) {
    // 异常处理
}

AutoCloseable 接口

使用 try-with-resources 时,无需手动关闭实现了 AutoCloseable 接口的资源。在 try 代码块执行完毕后,系统会自动调用资源的 close() 方法来关闭资源。(你也可以自己实现该接口)

如果有需要,也可以使用try catch resources也可以继续使用finally在其中进行打印操作等


异常抑制的产生

正常情况下,如果try代码块中抛出了异常,则控制权转移到catch部分,在控制权跳转过程中,该资源会自动调用close()方法。 但是如果在用close()方法关闭该资源时,可能会抛出一个异常,该异常将被抑制; 而try代码块中抛出的异常,会被try-with-resources语句真正抛出。

类似传统的try-catch-finally语句块中也存在异常抑制。 如果在try语句块中抛出了异常,在控制权转移到调用栈上一层代码之前,finally语句块中的语句也会执行。 但是finally语句块在执行的过程中,也可能会抛出异常。如果finally语句块也抛出了异常,那么这个异常会往上传递,而之前try语句块中的那个异常就丢失了。

可以看到try-with-resources编译后的代码,如果try块与自动生成的close()方法中都出现了异常,那么抛出的只有try块中的异常,而close()方法中的异常只是被Throwable.addSuppressed()记录了下来,并不会被直接抛出。

处理方法

Java 7引入了Suppressed Exceptions的概念 通过Throwable.getSuppressed()来获取

try (ResourceType resource = new ResourceType()) {
    // 在try块中操作资源,可能抛出异常
} catch (ResourceOperationException e) {
    // 捕获并处理资源关闭时的异常
    Throwable[] suppressed = e.getSuppressed();
    for (Throwable t : suppressed) {
        // 处理或记录抑制的异常
    }
}

自动关闭问题

  • try-with-resources 特性会先关闭流,再抛出异常,在使用时要注意,要考虑出异常时,这个流可不可以关闭。
  • 流关闭后,数据再也写不到缓冲区中,同时 nio 的 堆内内存缓存区 HeapByteBuffer 中的数据仍然是旧的。后面不管怎么 flush 都无法给到有效反馈信息给前端。

try-with-resources变量

  • try-with-resource中声明的变量会隐式的加上final 关键字,无法被更改 为了防止在try块中改变了变量的引用,导致关闭资源失效

JDK9优化

  • JDK7/8只能在try中声明,JDK9中可以先声明 ,把变量放在try中即可实现自动回收

总结

在处理必须关闭的资源时,使用 try-with-resources 语句替代 try-finally 语句没有任何问题。
生成的代码更简洁,更清晰,并且生成的异常更有用,也不会出错。

当有一些资源出现异常后并不能关闭的时候,使用该语法糖就要注意了。

References

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值