Java中如何优雅地关闭资源
关于Java中的资源关闭,是一个常见的问题,也是最容易被初级程序员忽略的一个问题,这个问题的严重性,吃过亏的人都知道,不需多说。之所以会出现这个问题,主要还是在Java 7之前,语言没有很好地提供资源管理的语法。我们先看下面的代码:
声明的资源必须放在try语句块的外面,最后在finally中关闭。这里存在很多容易导致问题的地方:
1、声明的资源在try语句块中打开后,忘记在finally中关闭;
2、关闭资源的代码没有放在try-catch块中,一旦牵涉到多种资源的关闭,前面的抛异常,后面的被跳过,导致对应的关闭代码没有执行;
3、如果资源的关闭没有放在finally中,也会导致打开的资源没有正常关闭。
这些问题比较隐蔽,如果代码相对比较复杂,就非常容易被忽略。还有一个问题,就是代码很长,非常丑陋,非常不利于维护。当然,这个问题很容易想到解决方案,就是把资源关闭的代码抽出来,形成一个公共的工具方法,就像下面这样:
由于java.sql.Connection,java.sql.PreparedStatement都没有实现java.io.Closeable接口,所以,这个公共的方法使用不了,当然,我们重新再定义带这两种参数的重载方法就行了,就像下面这样:
最后,我们的代码像下面的样子:
OK,这已经比开始简化了不少,如果没有更进一步的追求,到此打住也无可厚非。但我们再仔细研究下就会发现依然存在以下问题:
1、待关闭的资源必须要在最外层声明,有多少种就要声明多少次,这和Java变量声明的原则(哪里用哪里声明)不一致;
2、声明多少次,就要调用多少次close,还是容易遗漏。
那最好的方案是什么呢?请看下面的代码:
引入MyCloser,变量用的时候再声明,不用放到最外面,资源的关闭,在finally中一行代码解决。下面是MyCloser的代码:
这是一个典型的适配器模式,因为Google的Guava框架提供的Closer资源管理器只支持实现了java.io.Closeable的资源,对于像java.sql包中的资源,都没有实现该接口,因此,MyCloser提供了对应的适配,使所有的资源管理模式一致。在Java 7之前,这应该是最优雅的资源管理方案。
在Java 7及之后,我们可以使用最新的资源管理语法try-with-resource,上面的代码可以这么写:
可以看到,我们不用关心资源的关闭了,只要在try()中声明即可,这样的代码是最简洁也是最具表现力的,如果生产环境支持Java 7,最先考虑的应该是这个方案。
当然,由于历史原因,我们可能用到了一些第三方的包,牵涉到资源关闭,但对应的类却没有实现java.lang.AutoCloseable接口,当然也就不能使用try-with-resource语法来操作了,这时,有两种办法,一是提供一个适配的子类,实现java.lang.AutoCloseable接口,在其close中实现资源关闭逻辑,这样就能使用try-with-resource语法了;第二种就是使用MyCloser方案。推荐第一种,因为更简单。
作者:卓德方
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区),文章链接,文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:hwclouds.bbs@huawei.com进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。
- 点赞
- 收藏
- 关注作者
评论(0)