使用 "try with resources" 来创建没有任何引用的资源

Using "try with resources" for resources created without any reference

考虑以下情况:

try (ResultSet resultSet = DriverManager.getConnection("jdbc:...", "user", "pass")
                                      .createStatement().executeQuery(sql)) {    
                    .
                    .
                    .
}

这是在 try 个资源中创建了三个资源的情况:一个 Connection、一个 Statement 和一个 ResultSet

try块结束后这三个资源会发生什么?它们会全部关闭吗,即使它们没有任何引用,还是只会关闭 resultSet

在尝试使用资源块时声明 AutoCloseable 资源而不引用它们是否安全?

只有ResultSet会被关闭。如果要关闭多个资源,需要单独声明:

try (Connection conn  = DriverManager.getConnection("jdbc:...", "user", "pass");
     Statement stmt = conn.createStatement();
     ResultSet resultSet = stmt.executeQuery(sql)) {    

     // do stuff...
}

您也可以使用多种资源来做到这一点:

try (Connection c = DriverManager.getConnection("jdbc:...", "user", "pass");
     Statement s = c.createStatement();
     ResultSet resultSet = s.executeQuery(sql)) {
   //...
}

所有实现 AutoClosable 接口的变量在 try 块执行后关闭。

您的代码只会关闭 ResultSet,而 ConnectionStatement 打开。

在你的情况下,如果你不重用 ConnectionStatement,要关闭它们,请注意 try-with-resources 支持多个语句:

try (Connection connection = DriverManager.getConnection(...);
     Statement statement = connection.createStatement();
     ResultSet resultSet = statement.executeQuery(...)) {
    ...
}

Is this safe to declare AutoCloseable resources without any reference to them in try with resource blocks?

是也不是。那些没有分配给资源变量的资源不会被这段代码自动关闭。因此:

  • “是”这些资源仍然可以“安全”地通过在 try 块中对 ResultSet 的操作使用。
  • “不”那些资源会泄漏,这很容易在以后引起问题。

由于我将“安全”解释为两者,我考虑过的答案是“不”,它不安全。

唯一会被 try-with-resources 自动关闭的资源是分配给资源变量的资源。所以正确的写法是:

try (Connection connection = DriverManager.getConnection(...);
     Statement statement = connection.createStatement();
     ResultSet resultSet = statement.executeQuery(sql)) {
    // ...   
}

请注意,资源变量的自动关闭顺序与它们声明的顺序相反。


请注意,您通常可以侥幸逃脱。例如:

try (BufferedWriter bw = new BufferedWriter(new FileWriter(...)) {
    // ...   
}

除非在极不寻常的情况下,否则很可能没问题。当 bw 自动关闭时,它的 close() 方法调用 FileWriter 上的 close()。这可能会泄漏资源的唯一情况是 BufferedWriter 创建/构造失败。我认为只有在您不幸获得 OOME 时才有可能。 (而且 OOME 很可能会触发一个完整的垃圾收集,无论如何都会找到并关闭丢弃的资源......)

它不会关闭所有三个资源,因为您没有分别创建每个资源后跟分号。如果您单独创建每个资源,它将被关闭。 例如:

 try (
            Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/", "root", "password");
            Statement stmt = connection.createStatement();
            ResultSet rs = stmt.executeQuery(sql)
            ){}

这会起作用,因为 try-with-resources 语句会以与打开资源相反的顺序关闭资源。 我们可以使用实现 AutoCloseable 的对象来尝试使用资源,如果它没有实现,那么它需要在最终的黑色中关闭。 您可以在此处查看更多详细信息 https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html