我不会在最后的 blcok 中使用 try-catch 语句。(爪哇)



下面是一些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) {}
    }

所以我认为code

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

但我看到'流对象未被垃圾收集'

我不会在finally块中使用try-catch语句。请给我另一条路。

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

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;这是一件坏事。

如果使用Guava,还可以使用Closeables.closeQuietly(),它的功能与上面的代码基本相同。你也可以看看Closer,这是非常有趣的。

最后(双关语):如果您使用Java 7,请使用try-with-resources语句来代替(参见AutoCloseable):

try (
    conn = whatever();
) {
    // ...
}

另一种解决方法是将方法内部的catch全部删除:

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中声明。

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

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

为什么?

考虑一下:

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

Q1:如果在"做一些事情"代码中抛出异常会发生什么?

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

答案: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给出了"try with resource"实际做什么的细节。)


记录:

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

  • 分配null不会导致对象被关闭。它甚至不会导致垃圾回收。充其量,它可以使对象符合进行垃圾收集…

  • Exception真是个坏主意。阅读这篇文章:需要权威的来源来解释为什么你不应该抛出或捕获java.lang.Exception

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

从Java 7开始,它应该是这个

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

Connection conn = DriverManager.getConnection();
try {
  ...
} finally {
    conn.close();
}

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

你唯一需要知道的是,任何时候你得到一个连接,你必须关闭它(因此最后块),否则你可能会让该连接在你的应用程序中打开,最终耗尽可用的连接。

让其他人做try-catch的东西,并使用Apache Commons IOUtils

其中一个closeQuietly() -方法(例如这个)应该是你所需要的:

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

相关内容

  • 没有找到相关文章

最新更新