Java SE 7 的特性 try-with-resources
语句,你用过吗?为什么会有这篇文章呢?主要是在写 Java EE 小白入门专栏时,在 JDBC 章节中有提到过:JDBC 编程基本步骤中一般最后一步是关闭相关资源,可能涉及到 Connection
、PreparedStatement
、ResultSet
资源关闭。在 Java SE 7 及更高版本中我们可以使用 try-with-resources
语句进行优化,但是由于看到示例代码,觉得使用后会有点乱,自己不适应,就没有去尝试。现在想想既然官方有这个特性,明确说明可以简化代码,那说明并不是我想的那样,所以就有了这篇文章。
首先我们来看官方的说明:
try-with-resources
语句是声明一个或多个资源的try
语句。资源是一个对象,在程序使用完它之后必须关闭它。try-with-resources
语句确保在语句结束时关闭每个资源。任何实现java.lang.AutoCloseable
,它包括所有实现java.io.AutoCloseable
的对象,都可作为资源使用。
个人觉得官方说得比较清楚,凡是实现了 java.lang.AutoCloseable
或 java.io.AutoCloseable
的资源对象,都可以使用 try-with-resources
语句,在 try
块中语句执行结束后,资源自动关闭。就是这个意思。
那么 try-with-resources
是 Java 7 及更高版本中引入的一个特性,用于更好地管理资源,如文件、网络连接、数据库连接等。这个特性的主要目标是自动关闭在 try
块中打开的资源,无论 try
块是否正常结束或抛出异常。这有助于防止资源泄漏,并使代码更易于理解和维护。
try-with-resources
的基本语法如下:
try (Resource resource = new Resource()) {
// 使用资源进行操作
} // 这里,无论 try 块是否正常结束或抛出异常,资源都将被自动关闭
其中,Resource
是实现了 java.lang.AutoCloseable
接口的类。也就意味着此类必须实现 close()
方法,该方法在资源不再需要时被调用以执行清理操作。注意使用 try-with-resources
语句时,需要将资源类实例放在 try
语句的括号内,由 Java 自动管理资源的关闭。
现在,我们来看一个具体的例子。假设我们有一个需要从文件中读取数据的程序,我们希望在读取完成后关闭文件资源。在没有 try-with-resources
的情况下,我们的伪代码如下:
File file = new File("demo.txt");
FileReader reader = null;
try {
reader = new FileReader(file);
// 从文件中读取数据
} catch (IOException e) {
// 处理异常
} finally {
// 关闭资源
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
// 处理关闭文件时可能出现的异常
}
}
}
很明显,我们要在 finally
块中去关闭资源,这样一来无论程序正常运行还是出现异常都能保证 FileReader
资源的关闭。
我们再使用 try-with-resources
,可以简化代码:
try (FileReader reader = new FileReader(new File("demo.txt"))) {
// 从文件中读取数据
} catch (IOException e) {
// 处理异常
}
对比来看,代码是不是简化了很多。在上述代码中,无论 try
块是否正常结束或抛出异常,FileReader
都会被自动关闭。这是通过在 try
块结束后调用 FileReader
的 close()
方法实现的。注意,如果你没有捕获可能抛出的异常,那么你可能需要在一个单独的 catch
块中处理它们。
try-with-resources
可以帮助我们自动关闭资源,简化代码。那么在 JDBC 编程中,try-with-resources
主要用于管理数据库的连接操作资源的关闭。这个特性可以确保即使在处理过程中出现异常,数据库的连接操作相关资源也能被正确关闭。
我们还是先来看一下没有使用 try-with-resources
的 JDBC 编程基本示例:
public class TestNoTryWithResources {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
// 加载数据库驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 创建数据库连接
connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test_jdbc?serverTimezone=Asia/Shanghai", "root", "root");
// 创建PreparedStatement对象,预编译SQL语句
String sql = "select * from teacher where id = ?";
preparedStatement = connection.prepareStatement(sql);
// 设置参数
preparedStatement.setInt(1, 1);
// 执行SQL查询语句
resultSet = preparedStatement.executeQuery();
// 处理查询结果
while (resultSet.next()) {
System.out.println(resultSet.getString("name"));
}
} catch (ClassNotFoundException | SQLException e) {
// 异常处理
e.printStackTrace();
} finally {
// 在finally块中关闭资源,确保资源总是被关闭
try {
if (resultSet != null) {
resultSet.close();
}
if (preparedStatement != null) {
preparedStatement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
如果使用 try-with-resources
,我们可以将资源的关闭放在 try
语句括号中,如下所示:
public class TestTryWithResources {
public static void main(String[] args) {
String url = "jdbc:mysql://127.0.0.1:3306/test_jdbc?serverTimezone=Asia/Shanghai";
String user = "root";
String password = "root";
String sql = "select * from teacher where id = ?";
try {
// 加载数据库驱动
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 声明数据库连接、预编译语句资源对象
try (Connection connection = DriverManager.getConnection(url, user, password);
PreparedStatement preparedStatement = connection.prepareStatement(sql);){
// 设置参数
preparedStatement.setInt(1, 1);
// 执行SQL查询语句,声明ResultSet资源对象
try(ResultSet resultSet = preparedStatement.executeQuery();) {
// 处理查询结果
while (resultSet.next()) {
System.out.println(resultSet.getString("name"));
}
} catch (SQLException e) {
e.printStackTrace();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
在上述代码中,Connection
、PreparedStatement
和 ResultSet
都实现了 AutoCloseable
接口,因此它们可以被 try-with-resources
自动关闭。
// Connection继承了AutoCloseable接口
public interface Connection extends Wrapper, AutoCloseable {}
// PreparedStatement继承了Statement接口
public interface PreparedStatement extends Statement {}
// Statement继承了AutoCloseable
public interface Statement extends Wrapper, AutoCloseable {}
// ResultSet继承了AutoCloseable
public interface ResultSet extends Wrapper, AutoCloseable {}
在 JDBC编程中使用 try-with-resources
语句时,我们将资源的初始化放在 try
语句的括号内,Connection
、PreparedStatement
声明在一个 try
括号中,每条语句,都是 ;
号结尾。这样就可以确保在 try
块执行完毕后这些资源会被自动关闭。对于 try{}
块中的 ResultSet
资源,也需要单独放在一个 try
括号中,这样执行完可以被自动关闭。所以我们学习时要谨记其规则。
当我们在 JDBC 中使用 try-with-resources
语句,大家觉得代码简化了吗?
try-with-resources
特性属于 Java SE 7 模块。更具体地说,这是 Java 7 引入的一个新特性,旨在简化代码,减少资源泄漏。try-with-resources
语句可以自动关闭实现了 AutoCloseable
接口的资源,无论 try
块是否抛出异常。这个特性主要被用于数据库连接、文件操作等需要打开和关闭资源的场景。
需要注意的是:try-with-resources
语句中声明的资源只有在 try
块的括号内才能被正确关闭。如果在 try
块之外声明资源,那么该资源将不会被自动关闭。