博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用try-with-resources替代try finally释放资源
阅读量:6719 次
发布时间:2019-06-25

本文共 4007 字,大约阅读时间需要 13 分钟。

hot3.png

1、旧社会

Java里,对于文件操作IO流、数据库连接等开销非常昂贵的资源,用完之后必须及时通过close方法将其关闭,否则资源会一直处于打开状态,直至程序停止,增加系统负担。

关闭资源的常用方式就是在finally块里是释放,即调用close方法。比如,我们经常会写这样的代码:

public static void main(String[] args) {    BufferedReader br = null;    try {        String line;        br = new BufferedReader(new FileReader("d:\\testing.txt"));        while ((line = br.readLine()) != null) {            System.out.println(line);        }    } catch (IOException e) {        // handle exception    } finally {        try {            if (br != null) {                br.close();            }        } catch (IOException ex) {            // handle exception        }    }}

可以看出,为了关闭资源以及处理关闭资源时可能出现的异常,不得不写一大推代码。

2、新时代

2.1 使用新写法

从Java 7开始,jdk提供了一种更好的方式关闭资源,使用try-with-resources语句,改写一下上面的代码,效果如下:

public static void main(String[] args) {    try(BufferedReader br = new BufferedReader(new FileReader("d:\\testing.txt"))) {        String line;        while ((line = br.readLine()) != null) {            System.out.println(line);        }    } catch (IOException e) {        // handle exception    }}

清爽了很多是不是? 但是,有没有一点不安呢?

2.2 新问题

原来释放资源的时候如果发生异常,我们可以在finally块中catch新异常,然后继续处理。但是新方式没有了finally块,异常是如何抛出的?如果关闭资源时发生异常怎么办?我们怎么处理?

从文档上可以找到这样一段描述:

If an exception is thrown from the try block and one or more exceptions are thrown from the try-with-resources statement, then those exceptions thrown from the try-with-resources statement are suppressed. You can retrieve these suppressed exceptions by calling the Throwable.getSuppressed method from the exception thrown by the try block.

意思是:如果 try 块抛出异常并且 try-with-resources 语句抛出一个或多个异常,那么从 try-with-resources 语句中抛出的异常将会被忽略。你可以通过调用由 try块抛出的异常的Throwable.getSuppressed 方法检索这些被忽略的异常信息。

在明确一点说就是:

  • 如果try块异常,catch到的是try块抛出的异常;
  • 如果try块正常,close异常,catch到的是close抛出的异常;
  • 如果try块异常,close也异常,catch到的是try块抛出的异常,close异常被忽略。

基于这几种情况,我们做几个测试分别验证一下:

2.2.1 try块异常

大家都懂,略。

2.2.2 try块正常,close异常

public class TestTryWithResources {    public static void main(String[] args) {        try (MyResource resource = new MyResource()) {                    } catch (Exception e) {            System.out.println("捕获异常: " + e.getMessage());        }    }}/** * 自定义一个资源类,close时抛出异常 * * ps:只有实现AutoCloseable或Closeable接口的对象才能用try-with-resources */class MyResource implements AutoCloseable {    @Override    public void close() throws Exception {        System.out.println("执行close方法,释放资源");        throw new Exception("释放资源异常");    }}

执行结果为: 执行close方法,释放资源 捕获异常: 释放资源异常

即,catch到的是close方法抛出的异常

2.2.3 try块异常,close也异常

public class TestTryWithResources {    public static void main(String[] args) {        try (MyResource resource = new MyResource()) {            throw new Exception("try块异常");        } catch (Exception e) {            System.out.println("捕获异常: " + e.getMessage());            // 找到被忽略的异常            Throwable[] ts = e.getSuppressed();            for(Throwable t : ts) {                System.out.println("被忽略的异常"+ t.getMessage());            }        }    }}/** * 自定义一个资源类,close时抛出异常 */class MyResource implements AutoCloseable {    @Override    public void close() throws Exception {        System.out.println("执行close方法,释放资源");        throw new Exception("释放资源异常");    }}

执行结果: 执行close方法,释放资源 捕获异常: try块异常 被忽略的异常: 释放资源异常

即,catch到的是try块中的异常,释放资源时产生的异常被忽略了。

2.3 实践中的问题

实际上,很多时候try块中的异常和close方法抛出的异常是同一类型的。比如流、网络等不论是try块还是close方法都是抛出IOException,我们该怎么办? 最佳实践:按异常栈最底层的方法名判断。如果是close方法抛出的异常,就是关闭资源时产生的。 注:我们的方法名不能叫close

public class TestTryWithResources {    public static void main(String[] args) {        try (MyResource resource = new MyResource()) {            throw new Exception("try块异常");        } catch (Exception e) {            if(!"close".equals(e.getStackTrace()[0].getMethodName())){                System.out.println("处理业务异常");            }        }    }}/** * 自定义一个资源类,close时抛出异常 */class MyResource implements AutoCloseable {    @Override    public void close() throws Exception {        System.out.println("执行close方法,释放资源");        throw new Exception("释放资源异常");    }}

转载于:https://my.oschina.net/u/145060/blog/701357

你可能感兴趣的文章
使用Extended Events收集错误信息
查看>>
前端开发中的MCRV模式
查看>>
Lync Server 2013音视频网络流量带宽优化
查看>>
PfSense基于BSD的软件防火墙的安装、配置与应用
查看>>
“对于目标文件系统,目标文件过大,无法复制
查看>>
Castle IOC容器构建配置详解(二)
查看>>
IT图书创作中要注意的多与少
查看>>
Hyper-V 3.0功能部署PART 2:防火墙和证书
查看>>
SQL2K数据库开发二十三之索引操作重建索引
查看>>
用IE删除软件删除IE出现问题解决方法
查看>>
从“窃听门”事件解读手机Rootkit攻击
查看>>
[Android学习笔记三] Support v7提供交错式网格布局开发示例
查看>>
QoS令牌桶工作原理
查看>>
重提URL Rewrite(4):不同级别URL Rewrite的一些细节与特点
查看>>
linux子系统的初始化_subsys_initcall()【转】
查看>>
x60系统安装步骤
查看>>
Linux内核同步机制之(三):memory barrier【转】
查看>>
安装Fedora 24后必要的设置
查看>>
ES JVM使用如果超过75%就会GC较多,导致ES索引性能下降
查看>>
elasticsearch源码分析之search模块(server端)
查看>>