9. 使用 try-with-resources 语句替代 try-finally 语句

      从以往来看,try-finally 语句是保证资源正确关闭的最佳方式,即使是在程序抛出异常或返回的情况下:

      这可能看起来并不坏,但是当添加第二个资源时,情况会变得更糟:

      即使是用 try-finally 语句关闭资源的正确代码,如前面两个代码示例所示,也有一个微妙的缺陷。 try-with-resources 块和 finally 块中的代码都可以抛出异常。 例如,在 firstLineOfFile 方法中,由于底层物理设备发生故障,对 方法的调用可能会引发异常,并且由于相同的原因,调用 close 方法可能会失败。 在这种情况下,第二个异常完全冲掉了第一个异常。 在异常堆栈跟踪中没有第一个异常的记录,这可能使实际系统中的调试非常复杂——通常这是你想要诊断问题的第一个异常。 虽然可以编写代码来抑制第二个异常,但是实际上没有人这样做,因为它太冗长了。

      当 Java 7 引入了 try-with-resources 语句时,所有这些问题一下子都得到了解决[JLS,14.20.3]。要使用这个构造,资源必须实现 AutoCloseable 接口,该接口由一个返回为 voidclose 组成。Java 类库和第三方类库中的许多类和接口现在都实现或继承了 AutoCloseable 接口。如果你编写的类表示必须关闭的资源,那么这个类也应该实现 接口。

      以下是我们的第二个使用 try-with-resources 的示例:

      不仅 try-with-resources 版本比原始版本更精简,更好的可读性,而且它们提供了更好的诊断。 考虑 firstLineOfFile 方法。 如果调用 readLine 和(不可见)close 方法都抛出异常,则后一个异常将被抑制(suppressed),而不是前者。 事实上,为了保留你真正想看到的异常,可能会抑制多个异常。 这些抑制的异常没有被抛弃, 而是打印在堆栈跟踪中,并标注为被抑制了。 你也可以使用 getSuppressed 方法以编程方式访问它们,该方法在 Java 7 中已添加到的 Throwable 中。

      结论很明确:在处理必须关闭的资源时,使用 try-with-resources 语句替代 try-finally 语句。 生成的代码更简洁,更清晰,并且生成的异常更有用。 try-with-resources 语句在编写必须关闭资源的代码时会更容易,也不会出错,而使用 try-finally 语句实际上是不可能的。