try-with-resources 模式
本课属于 Coddy Java 学习旅程的“面向对象编程”单元。第 62 课,共 87 课。
使用文件流或数据库连接等资源时,完成后必须始终将它们关闭。否则可能导致内存泄漏。传统方法会使用 finally 块,但这种写法冗长且容易出错。
Java 的 try-with-resources 语句会在代码块执行完毕时自动关闭资源。任何实现了 AutoCloseable 接口的类都可以使用这种语法:
// 传统方式:代码冗长,还有风险
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("file.txt"));
String line = reader.readLine();
} finally {
if (reader != null) {
reader.close(); // 这里也可能抛出异常!
}
}
// Try-with-resources:简洁又安全
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
String line = reader.readLine();
} // 在这里自动关闭你可以用分号分隔多个资源来进行管理。它们会按照声明顺序的相反顺序关闭:
try (FileReader fr = new FileReader("input.txt");
BufferedReader br = new BufferedReader(fr)) {
// 使用这两个资源
} // 先关闭 br,再关闭 fr要创建自己的自动关闭类,请实现 AutoCloseable 接口及其唯一的 close() 方法:
public class DatabaseConnection implements AutoCloseable {
public DatabaseConnection() {
System.out.println("Connection opened");
}
@Override
public void close() {
System.out.println("Connection closed");
}
}这种模式可确保资源始终得到妥善释放,即使处理过程中发生异常也不例外。
挑战
简单让我们构建一个资源管理系统,展示 try-with-resources 的强大之处!你将创建可自动关闭的自定义类,模拟管理连接和会话,确保它们始终得到妥善清理。
你将把代码分成三个文件:
Connection.java:创建一个模拟数据库连接的类。你的Connection类应实现AutoCloseable。它需要一个用于存储连接名称(String)的私有字段,一个接收名称并打印[name] connection opened的构造函数,一个打印Executing on [name]: [sql]的query(String sql)方法,以及必需的close()方法,该方法会打印[name] connection closed。Session.java:再创建一个模拟用户会话的可自动关闭类。你的Session类也应实现AutoCloseable。添加一个用于存储用户名(String)的私有字段,一个接收用户名并打印Session started for [username]的构造函数,一个打印[username] performed: [action]的performAction(String action)方法,以及一个打印Session ended for [username]的close()方法。Main.java:把资源管理系统组合起来!你将收到三个输入:连接名称、用户名和要执行的操作。首先,演示单个资源的管理。打印
=== Single Resource ===,然后使用 try-with-resources 创建一个名称为给定值的Connection。在 try 代码块中,调用query("SELECT * FROM users")。代码块结束时,连接应自动关闭。接下来,演示多个资源的管理。先打印一个空行,然后打印
=== Multiple Resources ===。使用 try-with-resources,同时声明一个Connection(使用相同的名称)和一个Session(使用用户名),并按此顺序用分号分隔。在 try 代码块中,先对连接调用query("INSERT INTO logs"),然后对会话调用performAction,并传入输入的操作。留意资源关闭的顺序是相反的!
你将依次收到三个输入:连接名称(String)、用户名(String)和操作(String)。
注意,try-with-resources 无需显式调用 close,也无需使用 finally 代码块。即使发生异常,也能确保资源关闭;多个资源则会按声明顺序的相反顺序关闭!
亲手试试
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String connectionName = scanner.nextLine();
String username = scanner.nextLine();
String action = scanner.nextLine();
// === Single Resource ===
// TODO: 打印标题
// TODO: 使用 try-with-resources 创建 Connection
// TODO: 在 try 代码块中调用 query("SELECT * FROM users")
// === Multiple Resources ===
// TODO: 打印一个空行和标题
// TODO: 使用 try-with-resources 同时管理 Connection 和 Session
// TODO: 在 try 代码块中:
// - 在连接上调用 query("INSERT INTO logs")
// - 在会话上调用 performAction,传入输入的 action
}
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Java 在线编译器