这是一些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;
}
但我看到'Stream object not Garbage Collected。'
我不会在finally块中使用try-catch语句。 请给我另一种方式。
答案 0 :(得分: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
个;这是一件坏事(tm)。
如果你使用Guava,你也可以使用Closeables.closeQuietly()
,它与上面的代码完全相同。您也可以查看Closer
,这非常有趣。
最后(双关语):如果使用Java 7,请改用try-with-resources语句(参见AutoCloseable
):
try (
conn = whatever();
) {
// ...
}
答案 1 :(得分:1)
解决此问题的另一个方法是在方法中删除所有内容:
public void someWork() throws SQLException{
Connection c;
try {
// do something
} finally {
if (conn != null){
c.close();
}
}
}
然后,您在调用someWork
方法的main方法中的方法外部进行错误检查,或者将其包装在另一个调用someWork()
的方法中:
public void callSomeWork(){
try{
someWork();
}catch(SQLException ex){
//handle SQL error here
}
}
这样在try或finally中抛出的错误将在一个SQLException中声明。
答案 2 :(得分:1)
您可能不喜欢该代码,但在这种情况下,这是必要的。 (虽然你可以用@ fge' s closeQuietly
方法包装代码。)
但是存在一个更基本的问题。更改someWork
以关闭finally
块中的连接不足以以防止泄漏......在这种情况下!!
为什么?
考虑一下:
SomeClass sc = new SomeClass(createConnection());
// do some stuff
sc.someWork();
Q1:如果在"中做了一些异常,会发生什么事情"码?
Q2:如果在创建/构建SomeClass
时抛出异常会怎样? (注意:即使使用最简单的构造函数也可以这样做。例如,new
操作可能会引发OOME ...)
答案:Connection对象在两个基地都泄露了!
修复是在try / catch / finally之前或之前分配资源(例如Connection对象); e.g。
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
是一个非常糟糕的主意。请阅读:Need authoritative source for why you shouldn't throw or catch java.lang.Exception
答案 3 :(得分:0)
如果未关闭,您可能会离开僵尸连接并设置为NULL。
答案 4 :(得分:0)
让别人做try-catch-stuff并使用Apache Commons IOUtils
其中一个closeQuietly()
方法(例如this one)应该就是您所需要的:
等效于InputStream.close(),但将忽略任何异常。这个 通常用在finally块中。
答案 5 :(得分:0)
从Java 7开始,它就是这个
try (Connection conn = DriverManager.getConnection(props)) {
...
}
之前的Java 7
Connection conn = DriverManager.getConnection();
try {
...
} finally {
conn.close();
}
答案 6 :(得分:0)
如果您取消并且未关闭,请确保所有方法始终获得新的开放连接。
您唯一需要知道的是,只要您获得连接,必须关闭它(因此最终阻止),否则您可能会在您的应用程序中打开该连接并最终耗尽可用的连接。