## 使用try-with-resources语句替代try-finally语句 ### 示例 **示例代码**:[Item09Example01.java](CreatingAndDestroyingObjects/src/main/java/com/jueee/item09/Item09Example01.java) ### 说明 从以往来看,try-finally语句是保证资源正确关闭的最佳方式,即使是在程序抛出异常或返回的情况下: ```java // 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(); } } ``` 这可能看起来并不坏,但是当添加第二个资源时,情况会变得更糟: ```java // 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(); } } ``` 即使是用try-finally语句关闭资源的正确代码,如前面两个代码示例所示,也有一个微妙的缺陷。 try-with-resources块和finally块中的代码都可以抛出异常。 例如,在`firstLineOfFile`方法中,由于底层物理设备发生故障,对`readLine`方法的调用可能会引发异常,并且由于相同的原因,调用`close`方法可能会失败。 在这种情况下,第二个异常完全冲掉了第一个异常。 当Java 7引入了try-with-resources语句时,所有这些问题一下子都得到了解决。 要使用这个构造,资源必须实现 `AutoCloseable`接口,该接口由一个返回为`void`的`close`组成。Java类库和第三方类库中的许多类和接口现在都实现或继承了`AutoCloseable`接口。如果你编写的类表示必须关闭的资源,那么这个类也应该实现`AutoCloseable`接口。 以下是我们的第一个使用try-with-resources的示例: ```java // 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的示例: ```java // 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版本比原始版本更精简,更好的可读性,而且它们提供了更好的诊断。 可以在 try-with-resources语句中添加catch子句,就像在常规的try-finally语句中一样。这允许你处理异常,而不会在另一层嵌套中污染代码。作为一个稍微有些做作的例子,这里有一个版本的`firstLineOfFile`方法,它不会抛出异常,但是如果它不能打开或读取文件,则返回默认值: ```java // 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; } } ``` 结论明确:在处理必须关闭的资源时,使用try-with-resources语句替代try-finally语句。 生成的代码更简洁,更清晰,并且生成的异常更有用。 try-with-resources语句在编写必须关闭资源的代码时会更容易,也不会出错,而使用try-finally语句实际上是不可能的。