try-with-resources 是 Java 7 引入的一个重要特性,它是一种语法结构,用于自动管理(关闭)实现了 java.lang.AutoCloseable 或 java.io.Closeable 接口的资源。
它的主要目的是简化代码并确保资源被正确关闭,从而避免资源泄漏。常见的需要关闭的资源包括文件流(InputStream/OutputStream)、数据库连接(Connection)、Socket 连接等。
try-with-resources 之前 (传统方式)在 Java 7 之前,为了确保资源在任何情况下(无论是正常执行还是发生异常)都能被关闭,我们必须使用 try-catch-finally 结构。代码通常是这样的:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class OldTryCatchExample {
public static void main(String[] args) {
BufferedReader br = null; // 必须在 try 块外部声明,否则 finally 块访问不到
try {
br = new BufferedReader(new FileReader("file.txt"));
System.out.println(br.readLine());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) { // 必须检查是否为 null
try {
br.close(); // close() 方法本身也可能抛出异常
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
这种写法的缺点很明显:
finally 块,或者忘记在 finally 中关闭资源。finally 块中的 close() 方法也可能抛出异常,导致需要嵌套的 try-catch。try-with-resources (现代方式)try-with-resources 极大地简化了上述代码。它的语法是将资源的声明和初始化放在 try 关键字后面的圆括号 () 中。
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class NewTryWithResourcesExample {
public static void main(String[] args) {
// 将资源在 try() 中声明和初始化
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
// 在这里使用资源
System.out.println(br.readLine());
} catch (IOException e) {
// 处理异常
e.printStackTrace();
}
// 当 try 块执行完毕或发生异常时,br 会被自动关闭,无需手动调用 br.close()
}
}
它是如何工作的?
编译器会自动将 try-with-resources 语句转换为包含 finally 块的代码,并在 finally 块中调用资源的 close() 方法。你不再需要手动编写这个关闭逻辑。
try-with-resources 的核心优势代码更简洁、可读性更高:消除了所有关于资源关闭的模板代码,让开发者能更专注于业务逻辑。
更安全,自动关闭资源:无论 try 块是正常执行完成,还是因为异常(包括 return, break, continue)而退出,在括号中声明的资源都保证会被关闭,有效防止了资源泄漏。
支持管理多个资源:你可以在 try 后的括号中声明多个资源,用分号 ; 隔开。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipOutputStream;
public class MultiResourcesExample {
public static void main(String[] args) {
try (
FileInputStream fis = new FileInputStream("source.txt");
FileOutputStream fos = new FileOutputStream("target.zip");
ZipOutputStream zos = new ZipOutputStream(fos)
) {
// ... 使用 fis 和 zos ...
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) > 0) {
zos.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
// 在这里,zos, fos, fis 会被自动关闭
}
}
注意:多个资源的关闭顺序与它们的声明顺序相反。在上面的例子中,关闭顺序是 zos -> fos -> fis。这通常是正确的逻辑,因为后创建的资源可能依赖于先创建的资源。