BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

Java中的自动化资源管理

| 作者 Alex Blewitt 关注 4 他的粉丝 ,译者 张龙 关注 12 他的粉丝 发布于 2010年8月27日. 估计阅读时间: 6 分钟 | GMTC大前端的下一站,PWA、Web框架、Node等最新最热的大前端话题邀你一起共同探讨。

Project Coin的一个突出特点就是具备了自动化资源管理(即ARM)能力。其目的在于当遇到错误或是成功执行完代码块后能够轻松处理好外部资源。其最初实现位于OpenJDK中。考虑如下繁琐的文件拷贝操作,代码来自于Java Bytestream教程

 
FileInputStream in = null;
FileOutputStream out = null;
try {
  in = new FileInputStream("xanadu.txt");
  out = new FileOutputStream("outagain.txt");
  int c;
  while ((c = in.read()) != -1)
    out.write(c);
} finally {
  if (in != null)
    in.close();
  if (out != null)
    out.close();
}

上面不仅有大量的样版代码,而且InputStream.close()的文档表明它会抛出IOException(OutputStream也存在类似的异常,无论何种情况,要想成功编译这些代码,要么在外面加上catch块,要么将异常继续往外抛)。

try-catch-finally块的语义范围还要求变量FileInputStream in与FileOutputStream out声明在块的外面(如果定义在try块内,那么catch块与finally块就访问不到了)。

为了减少上面这些样版代码并且收紧块中所用的资源范围,Java语言在try块中新增了一些内容。最初的try-with-resources块(或者叫做ARM块)规范已经拥有实现了,随后该规范被纳入到JDK 7 build 105中。

新的接口java.lang.AutoCloseable被加到了提案API中,它只定义了一个会抛出Exception的方法close()。该接口是java.io.Closeable的父接口,这意味着所有的InputStream与OutputStream都会自动享受到该行为所带来的好处。此外,FileLock与ImageInputStream也实现了AutoCloseable接口。

这样,上面的代码就可以这样来写:

 
try (
  FileInputStream in = new FileInputStream("xanadu.txt");
  FileOutputStream out = new FileOutputStream("outagain.txt")
) {
  int c;
  while((c=in.read()) != -1 )
    out.write();
}

在try块的末尾,无论是正常结束还是抛出了异常,out与in资源都会自动调用close()方法。此外,与之前示例不同的是out.close()与in.close()保证会执行(在之前的示例中,一旦in.close()方法抛出了异常,随后的out.close()方法就没有机会执行了)。

关于这种方式,还有一些微妙之处值得我们注意:

  • 如上代码所示,在资源部分中,最后一个资源后面是不允许使用分号的。
  • 资源块使用()分隔,而不是常见的{},以此将其与现有的try块分隔开来。如果存在资源块,那么里面必须要包含一个或多个资源定义语句。
  • 每个资源定义具有如下形式:type var = expression;在资源块中不能使用通常的语句。
  • 资源都是隐式final的,也就是说即便没有使用final,这些资源也都是final的。如果尝试为资源变量赋值会得到一个编译期错误。
  • 资源必须是AutoCloseable的子类型,如果不是的话会得到一个编译期错误。
  • 资源关闭的顺序与定义的顺序正好相反。换句话说,在上面的代码示例中,out.close()要先于in.close()得到调用。这么做可以构建嵌套的流,然后从外向内关闭流,这要比按顺序关闭更好(也就是说,可以在底层的流关闭前先清空缓存)。
  • 每个块可以生成n+1个异常,n是资源的数量。这出现在代码主体抛出了异常,然后每个资源关闭语句也都抛出异常的情况下。在这种情况下,代码主体的异常将被抛出,但其他的异常将会被添加到异常的抑制列表(suppressed exception list)中。可以通过getSuppressedExceptions()方法访问这些异常信息。
  • 异常堆栈追踪信息可以带有Suppressed前缀:在这些情况下,序列化的Throwable格式也有所不同(如果Java 6客户端调用了远程Java 7运行时中的服务会出现这个问题,反之亦然)。
  • javax.swing与java.sql目前并不会加入到ARM中;类需要继承AutoCloseable才能为ARM所用。JDBC 4.1如果能够成为JDK 7的一部分,那么它也将支持ARM,但具体时间尚未确定。

能够移除Java开发者每天都要编写的样版代码对生产力的提升是个促进,虽然JDK 7具备了这种能力,但有时需要在编写代码前利用这种能力。很多库都需要重新编译以适应Java 6的需要,无论何时,只要使用了自动化资源管理,那么它就只能用于使用-target 7编译的代码。等到Java 6寿终正寝,并且Java 8发布后,使用ARM就会成为自然而然的事情了。

查看英文原文:Automatic Resource Management in Java

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

太丑了 by yao huang

难道没有人觉得Java的代码越来越不伦不类么?

我想在提供新的功能时,保持语言的概念完整性也很重要。

Re: 太丑了 by 张 明辉

其实这种写法与C#太相似了

Re: 太丑了 by Yang Bob

Java已经不是昨天的Java了,像.NET一样,掺杂了太多的语法,玩文字游戏了~不喜欢.NET正式如此,没想到java也沦落,还不如大力发展基于JVM的脚本语言来弥补动态和开发效率方面的不足,Java规规矩矩的服务于底层。

Re: 太丑了 by Jeffrey Zhao

你应该说是C#而不是.NET。我还是觉得挺奇怪的,因为按照你的审美观点,我觉得你不应该喜欢动态语言脚本语言才对啊,那边的“语法”、“文字游戏”比Java多多了……

Re: 太丑了 by Jeffrey Zhao

我觉得“概念”还是完整的,只是这种设计的确不好看……

很奇怪的语法 by Liu Nathan

Java添加了越来越多的语法,难道仅仅是为了开发时代码的简洁?!为了这些语法,又规定了新的语法……只是增加了学习曲线

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

6 讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT