mirror of
https://github.com/Jueee/effective-Java.git
synced 2025-03-14 03:10:42 +08:00
使用try-with-resources语句替代try-finally语句
This commit is contained in:
parent
f74869667a
commit
ca0267cf95
@ -32,3 +32,4 @@ finalizer机制有一个严重的安全问题:它们会打开你的类来进
|
||||
|
||||
Cleaner机制的规范说:“`System.exit`方法期间的清理行为是特定于实现的。 不保证清理行为是否被调用。”虽然规范没有说明,但对于正常的程序退出也是如此。 在我的机器上,将`System.gc()`方法添加到`Teenager`类的`main`方法足以让程序退出之前打印`Cleaning room`,但不能保证在你的机器上会看到相同的行为。
|
||||
|
||||
总之,除了作为一个安全网或者终止非关键的本地资源,不要使用Cleaner机制,或者是在Java 9发布之前的finalizers机制。即使是这样,也要当心不确定性和性能影响。
|
94
ch02创建和销毁对象/09.使用try-with-resources语句替代try-finally语句.md
Normal file
94
ch02创建和销毁对象/09.使用try-with-resources语句替代try-finally语句.md
Normal file
@ -0,0 +1,94 @@
|
||||
## 使用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语句实际上是不可能的。
|
@ -21,7 +21,7 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- https://projectlombok.org/changelog -->
|
||||
<!-- v1.18.4:PLATFORM: Many improvements for lombok's JDK10/11 support. -->
|
||||
<!-- v1.18.4: PLATFORM: Many improvements for lombok's JDK10/11 support. -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
|
@ -0,0 +1,70 @@
|
||||
package com.jueee.item09;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class Item09Example01 {
|
||||
|
||||
private static final int BUFFER_SIZE = 10000;
|
||||
|
||||
// try-finally - 不再是关闭资源的最佳方法!
|
||||
static String firstLineOfFile(String path) throws IOException {
|
||||
BufferedReader br = new BufferedReader(new FileReader(path));
|
||||
try {
|
||||
return br.readLine();
|
||||
} finally {
|
||||
br.close();
|
||||
}
|
||||
}
|
||||
|
||||
// try-finally 当添加第二个资源时,情况会变得更糟
|
||||
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-with-resources - 关闭资源的最佳方法!
|
||||
static String firstLineOfFileGood(String path) throws IOException {
|
||||
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
|
||||
return br.readLine();
|
||||
}
|
||||
}
|
||||
|
||||
// try-with-resources on multiple resources - 关闭资源的最佳方法!
|
||||
static void copyGood(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 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user