第9项:尽量使用try-with-resources而不是try-finally(Prefer try-with-resources to try-finally)
Java库包含许多必须通过调用close方法手动关闭的资源。 示例包括InputStream,OutputStream和java.sql.Connection。 关闭资源经常被客户忽视,可预见的可怕性能后果。 虽然其中许多资源使用终结方法作为安全网,但终结方法不能很好地工作(第8项)。
在之前的做法中(Historically),try-finally语句是保证资源正确关闭的最佳方式,即使出现异常或在return的时候(even in the face of an exception or return):
// 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();
}
}
可能很难相信,但即使是优秀的程序员也会在大多数时候弄错。对于初学者来说,我在Java Puzzlers [Bloch05]的第88页上弄错了,多年来没有人注意到。 事实上,2007年Java库中close方法的三分之二使用是错误的。
即使是使用try-finally语句关闭资源的正确代码,如前两个代码示例所示,也有一个微妙的缺陷。 try块和finally块中的代码都能够抛出异常。 例如,在firstLineOfFile方法中,对readLine的调用可能由于底层物理设备中的故障而引发异常,并且由于相同的原因,对close的调用可能会失败。 在这种情况下,第二个异常完全覆盖了第一个异常。 异常堆栈跟踪中没有第一个异常的记录,这可能会使实际系统中的调试变得非常复杂 - 通常第一个异常才是你要查看并诊断问题的关键所在(usually it’s the first exception that you want to see in order to diagnose the problem)。虽然有可能编写代码来抑制第二个异常而支持第一个异常,但几乎没有人这样做,因为它太冗长了。
当Java 7引入了try-with-resources语句[JLS,14.20.3]时,所有这些问题都得到了一举解决。 要使用此构造,资源必须实现AutoCloseable接口,该接口由单个返回类型为void的close方法组成。 Java库和第三方库中的许多类和接口现在实现或继承AutoCloseable。 如果编写一个代表必须关闭的资源的类( If you write a class that represents a resource that must be closed),那么你的类也应该实现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版本不仅比原始版本更短,更易读,而且它们提供了更好的诊断功能。 考虑firstLineOfFile方法。 如果readLine调用和关闭(不可见)资源时抛出异常,则后一个异常被抑制而有利于前者(the latter exception is suppressed in favor of the former)。 实际上,可以抑制多个异常以保留你实际想要查看的异常。 这些被抑制的异常不是被丢弃; 它们被打印在跟踪的堆栈中,并带有一个表示它们被压制了的符号。 你还可以使用getSuppressed方法以编程的方式访问它们,该方法已添加到Java 7中的Throwable中。
你可以将try子句放在try-with-resources语句中,就像在常规的try-finally语句中一样。 这允许你处理异常,而不会使用另一层嵌套来破坏你的代码。 作为一个有点设计想法的例子(As a slightly contrived example),这里是我们的firstLineOfFile方法的一个版本,它不会抛出异常,但如果无法打开文件或读取文件时,则返回默认值:
// 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;
}
}
这里经验教训是很明确的(The lesson is clear):在处理必须关闭的资源时,相比于try-finally,始终优先使用try-with-resources。 生成的代码更短更清晰,它生成的异常更有用。 try-with-resources语句可以在使用必须关闭的资源的同同时轻松编写正确的代码,使用try-finally几乎是不可能的。
关注个人公众号获取更新!
第9项:尽量使用try-with-resources而不是try-finally(Prefer try-with-resources to try-finally)的更多相关文章
- java resources 红叉 An error occurred while filtering resources
用eclipse创建了一个Spring mvc的Maven项目,在项目上有个叉叉,通过Window -> Show View -> Markers中看到错误原因 An error occu ...
- 条款一:尽量使用const、inline而不是#define
#define ASPECT_RATIO 1.653 编译器会永远也看不到ASPECT_RATIO这个符号名,因为在源码进入编译器之前,它会被预处理程序去掉,于是ASPECT_RATIO不会加入到符号 ...
- Spring Security – security none, filters none, access permitAll
1.概述 Spring Security提供了几种将请求模式配置为不安全或允许所有访问的机制.取决于这些机制中的哪一种 - 这可能意味着根本不在该路径上运行安全过滤器链,或者运行过滤器链并允许访问 2 ...
- WPF学习之资源-Resources
WPF学习之资源-Resources WPF通过资源来保存一些可以被重复利用的样式,对象定义以及一些传统的资源如二进制数据,图片等等,而在其支持上也更能体现出这些资源定义的优越性.比如通过Resour ...
- 在后台代码中动态生成pivot项并设置EventTrigger和Action的绑定
最近在做今日头条WP的过程中,遇到需要动态生成Pivot项的问题.第一个版本是把几个频道写死在xaml里了,事件绑定也写在xaml里,每个频道绑定一个ObservableCollection<A ...
- [安卓]应用程序资源(App Resources)
谷歌推荐我们,在开发安卓系统应用程序的时候,要把资源从代码中分离出来,这样便于我们单独维护它们.采取分离的资源设计,我们还可以提供可选资源,支持特定的设备配置譬如不同的语言或屏幕尺寸,随着越来越多的A ...
- 利用maven中resources插件的copy-resources目标进行资源copy和过滤
maven用可以利用如下配置进行资源过滤,pom.xml的配置如下: <build> <!-- 主资源目录 --> <resources> <resource ...
- Unity Android 5.6版本Resources.Load效率的问题
0x00 前言 相信不少使用Unity的小伙伴都听说过,甚至也亲身经历过在Unity5.6最初的几个版本中使用Resources.Load方法加载资源变--慢的问题. 这个问题的确是存在的,比如这个i ...
- 手把手教你解析Resources.arsc
http://blog.csdn.net/beyond702/article/details/51744082 一.前言 对于APK里面的Resources.arsc文件大家应该都知道是干什么的(不知 ...
- 解析Resources.arsc
一.前言 对于APK里面的Resources.arsc文件大家应该都知道是干什么的(不知道的请看我的另一篇文章Android应用程序资源文件的编译和打包原理),它实际上就是App的资源索引表.下面我会 ...
随机推荐
- 解决Axis2在webservice中遇到特殊字符的无法传输的缺陷(<CDATA>数据类型)
在使用Axis2进行soa webservice开发时,遇到类似以下的错误信息: com.ctc.wstx.sw.BaseStreamWriter.writeCharacters(BaseStream ...
- web界面上的字体兼容方案
原贴地址:http://www.baidufe.com/item/60cd11d3bfdee5c51369.html 做前端的,对web界面基本都抠的很仔细,尤其精确到1px! 类似边距.宽度.高度等 ...
- ubuntu 12.04修改环境变量PAT…
这里我只针对ubuntu 12.04进行了测试,由于不同的linux发行版本可能会有一些地方不一致,所以对于其他的linux发行版仅供参考. 1.直接在命令行里添加 我们先来看下下PATH的值 ec ...
- 23-从零玩转JavaWeb-单例设计模式
一.什么是设计模式 二.什么是单例设计模式 三.单例设计模式特点 四.单例设计模式优点 五.单例设计模式实现步骤 六.什么是工具类
- Using Browser Link in Visual Studio 2013
题记:Browser Link是VS 2013开始引入的一个强大功能,让前端代码(比如AngularJS的代码)在VS中的修改更加轻而易举. 前 端代码是运行在浏览器中,而Visual Studio通 ...
- 【bzoj2208】[Jsoi2010]连通数
2208: [Jsoi2010]连通数 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2305 Solved: 989[Submit][Status ...
- php 扩展开发
Linux下用C开发PHP扩展 一.首先下载PHP源码包,假设源码包目录为:/software/php-5.2.13 #> cd /software/php-5.2.13/ext 二.假设我们要 ...
- Luogu 4213 【模板】杜教筛(Sum)
当作杜教筛的笔记吧. 杜教筛 要求一个积性函数$f(i)$的前缀和,现在这个东西并不是很好算,那么我们考虑让它卷上另外一个积性函数$g(i)$,使$(f * g)$的前缀和变得方便计算,然后再反推出这 ...
- 框架和cms区别
cms:精装房,拎包即可入住 框架:毛坯房,内部装修可根据自己需求来 选择策略:个性化需求不高的话,可以选择cms
- SimpleTag——认识自定义标签
自定义标签 自定义标签的开发与应用步骤 编写完成标签功能的 Java 类(标签处理器) 编写标签库描述(tld)文件,在tld文件中对自定义中进行描述 在 JSP 页面中导入和使用自定义标签 ①. 创 ...