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)的更多相关文章

  1. java resources 红叉 An error occurred while filtering resources

    用eclipse创建了一个Spring mvc的Maven项目,在项目上有个叉叉,通过Window -> Show View -> Markers中看到错误原因 An error occu ...

  2. 条款一:尽量使用const、inline而不是#define

    #define ASPECT_RATIO 1.653 编译器会永远也看不到ASPECT_RATIO这个符号名,因为在源码进入编译器之前,它会被预处理程序去掉,于是ASPECT_RATIO不会加入到符号 ...

  3. Spring Security – security none, filters none, access permitAll

    1.概述 Spring Security提供了几种将请求模式配置为不安全或允许所有访问的机制.取决于这些机制中的哪一种 - 这可能意味着根本不在该路径上运行安全过滤器链,或者运行过滤器链并允许访问 2 ...

  4. WPF学习之资源-Resources

    WPF学习之资源-Resources WPF通过资源来保存一些可以被重复利用的样式,对象定义以及一些传统的资源如二进制数据,图片等等,而在其支持上也更能体现出这些资源定义的优越性.比如通过Resour ...

  5. 在后台代码中动态生成pivot项并设置EventTrigger和Action的绑定

    最近在做今日头条WP的过程中,遇到需要动态生成Pivot项的问题.第一个版本是把几个频道写死在xaml里了,事件绑定也写在xaml里,每个频道绑定一个ObservableCollection<A ...

  6. [安卓]应用程序资源(App Resources)

    谷歌推荐我们,在开发安卓系统应用程序的时候,要把资源从代码中分离出来,这样便于我们单独维护它们.采取分离的资源设计,我们还可以提供可选资源,支持特定的设备配置譬如不同的语言或屏幕尺寸,随着越来越多的A ...

  7. 利用maven中resources插件的copy-resources目标进行资源copy和过滤

    maven用可以利用如下配置进行资源过滤,pom.xml的配置如下: <build> <!-- 主资源目录 --> <resources> <resource ...

  8. Unity Android 5.6版本Resources.Load效率的问题

    0x00 前言 相信不少使用Unity的小伙伴都听说过,甚至也亲身经历过在Unity5.6最初的几个版本中使用Resources.Load方法加载资源变--慢的问题. 这个问题的确是存在的,比如这个i ...

  9. 手把手教你解析Resources.arsc

    http://blog.csdn.net/beyond702/article/details/51744082 一.前言 对于APK里面的Resources.arsc文件大家应该都知道是干什么的(不知 ...

  10. 解析Resources.arsc

    一.前言 对于APK里面的Resources.arsc文件大家应该都知道是干什么的(不知道的请看我的另一篇文章Android应用程序资源文件的编译和打包原理),它实际上就是App的资源索引表.下面我会 ...

随机推荐

  1. SqlServer——临时表

    1.表的类型: SqlServer数据库中分为两个表:永久表.临时表:通过表名的前缀区分. 永久表:与物理文件.C# 中的静态类 类似,任何用户均可对其执行操作并且相互影响: 临时表:简单的说就是使用 ...

  2. OpenGL ES & SDL(转载)

    原帖:http://qqwt.blog.sohu.com/91060365.html 这个学期在学习嵌入式,由于老师的高要求.所以我们几个水手必须要完成一个项目,名字就叫OpenGL ES & ...

  3. 安装saltstack-web管理界面

    1.安装salt-master.salt-minion和salt-api $ sudo yum install epel-release -y $ sudo yum install salt-mast ...

  4. webmagic使用

    webmagic是Java语言用于爬虫的工具.官网地址:http://webmagic.io/,中文文档地址:http://webmagic.io/docs/zh/ 使用webmagic有3种配置需要 ...

  5. A Look at the Razor View Engine in ASP.NET MVC

    The biggest architectural difference that exists between ASP.NET MVC and ASP.NET Web Forms is the ne ...

  6. Dubbo管理中心部署

    我们在开发时,需要知道注册中心都注册了哪些服务,以便我们开发和测试.我们可以通过部署一个管理中心来实现.其实管理中心就是一个web应用,部署到tomcat即可. 管理端的部署: 1,首先我们要编译源码 ...

  7. c++多线程编程(三)

    关于WaitForSingleObject函数用法 : 用户模式的线程同步机制效率高,如果需要考虑线程同步问题,应该首先考虑用户模式的线程同步方法. 但是,用户模式的线程同步有限制,对于多个进程之间的 ...

  8. 557. Reverse Words in a String III 翻转句子中的每一个单词

    [抄题]: Given a string, you need to reverse the order of characters in each word within a sentence whi ...

  9. 如何撤回经由Outlook2016刚发出的邮件

    在Outlook2016中,刚发出了一封邮件,发现有问题,想撤回,如何处理? 在对方尚未查看和接收时,可撤回. 参考步骤 1.选中这封邮件,用鼠标双击打开 2.点Move旁边的下拉按钮 3.点击&qu ...

  10. Schwartz kernel theorem施瓦兹核定理

    In mathematics, the Schwartz kernel theorem is a foundational result in the theory of generalized fu ...