0

这是一些java代码。

public class SomeClass {
private Connection connection;

public SomeClass(Connection c) {
    connection = c;
}
public void someWork(){
    Connection c;
    try {
        // do something
    } catch (Exception e) {
        // some exception code
    } finally {
        if (conn != null){
            try {c.close();} catch (Exception e) {}
        }
    }
}

}

但我不喜欢代码

if (conn != null){
        try {c.close();} catch (Exception e) {}
    }

所以我认为代码

...catch (Exception e) {
        // some exception code
    } finally {
        c = null;
    }

但我看到“流对象未收集垃圾”。

我不会在 finally 块中使用 try-catch 语句。请给我另一种方式。

4

7 回答 7

6

只需创建一个静态实用程序方法:

private static void closeQuietly(final Connection conn)
{
    if (conn == null)
        return;
    try {
        conn.close();
    } catch (WhateverException ignored) {
    }
}

然后

conn = whatever(); // create it there, not in the try block
try {
    // work
} catch (WhateverException e) {
    // whatever
} finally {
    closeQuietly(conn);
}

但最终,无论如何,您在 finally 块中使用 try/catch。

请注意,捕捉Exception是一个坏主意。捕获专门引发的异常conn.close()。捕捉Exception意味着你也捕捉到了所有RuntimeException的 s;那是一件坏事(tm)。

如果您使用 Guava,您也可以使用Closeables.closeQuietly(),它与上面的代码几乎相同。你也可以看看Closer,非常有趣。

最后(双关语):如果您使用 Java 7,请改用 try-with-resources 语句(请参阅 参考资料AutoCloseable):

try (
    conn = whatever();
) {
    // ...
}
于 2013-06-20T09:21:25.593 回答
1

另一种解决方法是在方法内一起删除捕获:

public void someWork() throws SQLException{
    Connection c;
    try {
        // do something
    } finally {
        if (conn != null){
            c.close();
        }
    }
}

然后,您在调用someWork方法的主方法中的方法之外进行错误检查,或者将其包装在另一个调用方法的方法中someWork()

 public void callSomeWork(){
    try{
     someWork();
    }catch(SQLException ex){
    //handle SQL error here
    }
 }

这样,try 或 finally 中抛出的错误将在一个 SQLException 中声明。

于 2013-06-20T09:31:01.907 回答
1

您可能不喜欢该代码,但在这种情况下它是必要的。(尽管您可以将代码包装在@fge 方法之类的closeQuietly方法中。)

但是还有一个更根本的问题。 更改someWork以关闭finally块中的连接不足以防止泄漏......在这种情况下!

为什么?

考虑一下:

SomeClass sc = new SomeClass(createConnection());
// do some stuff
sc.someWork();

Q1:如果在“do some stuff”代码中抛出异常会发生什么?

Q2:如果在创建/构造时抛出异常会发生什么SomeClass?(注意:即使使用最简单的构造函数也是可能的。例如,操作可能会抛出 OOME new...)

答案:Connection 对象被泄露......在两个基地!


解决方法是在 try / catch / finally 之内或之前分配资源(例如 Connection 对象);例如

Connection c = createConnection();
try {
    // do something
} catch (SomeException e) {
    // some exception code
} finally {
    if (c != null){
        try {c.close();} catch (SomeException e) {}
    }
}

在 Java 7 中,你也可以这样写:

try (Connection c = createConnection()) {
    // do something
} catch (SomeException e) {
    // some exception code
}

前提是Connection实现了AutoCloseable接口。Java 7 版本是一个更复杂的实现的“语法糖”,它负责智能地检查null、调用close()和处理任何产生的异常。(JLS 详细说明了“使用资源尝试”的实际作用。)


作为记录:

  • 问题不在于垃圾收集/收集。问题是Connection对象需要关闭

  • 分配null不会导致对象关闭。它甚至不会导致它被垃圾收集。充其量,它可以使对象有资格进行垃圾收集......在未来的一些 GC 运行中。

  • 捕捉Exception是一个非常糟糕的主意。阅读此内容:需要权威来源了解为什么不应该抛出或捕获 java.lang.Exception

于 2013-06-20T09:32:51.320 回答
0

如果未关闭并设置为 NULL,您可能会离开僵尸连接。

于 2013-06-20T09:21:49.977 回答
0

让其他人做 try-catch-stuff 并使用Apache Commons IOUtils

closeQuietly()-methods 之一(例如this one)应该正是您所需要的:

等效于 InputStream.close(),除了将忽略任何异常。这通常用于 finally 块中。

于 2013-06-20T09:23:03.667 回答
0

从 Java 7 开始,它应该是这样的

try (Connection conn = DriverManager.getConnection(props)) {
    ...
}

在 Java 7 之前

Connection conn = DriverManager.getConnection();
try {
  ...
} finally {
    conn.close();
}
于 2013-06-20T09:23:20.607 回答
0

如果您无效且未关闭,请确保所有方法始终获得新的打开连接。

您唯一需要知道的是,任何时候获得连接都必须关闭它(因此是 finally 块),否则您可能会在应用程序中保持该连接处于打开状态并最终用完可用连接。

于 2013-06-20T09:24:01.290 回答