【Effective Java 09】try-with-resources 优先于 try-finally
1. 使用 try-finally 关闭资源的缺点
Java 类库中包括许多必须通过调用 close 方法来手工关闭的资源。例如,InputStream
、OutputStream
和 java.sql.Connection
。客户端经常会忽略资源的关闭,造成严重的性能浪费。虽然这其中的许多资源都有终结方法作为 “安全网”,但是效果并不理想。
长久以来,try-finally语句式确保资源会被适时关闭的最佳方法,就算法发生异常或者返回也一样。
public class BadDemo {
public static String firstLineOfFiles(String path) throws IOException {
// try-finally - No Longer the best way to close resources
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
br.close();
}
}
public static void main(String[] args) {
try {
System.out.println(firstLineOfFiles("./hello.txt"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
这看起来好像也不太坏。有这种感觉只是因为需要关闭的资源少。如果需要关闭的资源过多,很快就一团糟了。
public class BadDemo {
public static final int BUFFER_SIZE = 4096;
public static void copy(String src, String dst) throws IOException {
InputStream is = new FileInputStream(src);
try {
OutputStream os = new FileOutputStream(dst);
try {
byte[] buf = new byte[BUFFER_SIZE];
int n;
while ((n = is.read(buf)) >= 0) {
os.write(buf, 0, n);
}
} finally {
os.close();
}
} finally {
is.close();
}
}
public static void main(String[] args) {
try {
copy("a.txt", "b.txt");
} catch (IOException e) {
e.printStackTrace();
}
}
}
这样做太繁琐了。
2. 使用 try-with-finally 关闭资源
Java 7 引入了 try-with-resources 解决了该问题。要使用这个构造的资源,必须先实现 AutoCloseable
接口,其中包含了单个返回 void
的 close
方法。 Java 类库与第三方类库中的许多类和接口,现在都实现或扩展了 AutoCloseable
接口。如果编写了一个类,它代表的是必须被关闭的资源,那么这个类也应该实现 AutoCloseable
。
public class GoodDemo {
public static final int BUFFER_SIZE = 4096;
public static void copy(String src, String dst) throws IOException {
// The Best Way to close resources !
try (
InputStream is = new FileInputStream(src);
OutputStream os = new FileOutputStream(dst)
) {
byte[] buf = new byte[BUFFER_SIZE];
int n;
while ((n = is.read(buf)) >= 0) {
os.write(buf, 0, n);
}
}
}
public static void main(String[] args) {
try {
copy("a.txt", "b.txt");
} catch (IOException e) {
e.printStackTrace();
}
}
}
使用 try-with-resources 不仅使得代码更简单易懂,更容易进行诊断。如果 readLine 和 不可见的 close 方法都抛出异常,后一个抛出的异常就会被禁止,以保留第一个异常。
很显然,在处理必须关闭的资源时,始终要优先考虑使用 try-with-resources,而不是使用 try-finally。