以下代码是否会导致资源泄漏?
JarOutputStream jo = null;
try
{
File f = new File("myinput.txt");
jo = new JarOutputStream(new FileOutputStream(f));
}
catch(IOException ex){
}
finally
{
try {
if(jo!=null)
jo.close();
} catch (IOException e) {
}
}
如果JarOutputStream
的创建失败,这会导致任何资源泄漏,因为FileOutputStream
已经构建了吗?
答案 0 :(得分:2)
假设,如果JarOutputStream
构造函数抛出异常,它会泄漏资源。 (当然,javadoc在这一点上并不清楚。)
但是,通过这种特殊用法,很难看出构造函数如何抛出异常。检查源代码(Java 6到Java 8)表明,此处可能发生的唯一异常是Error
的子类......您不应该尝试从中恢复。
这是不好的做法吗?
这实际上取决于背景。
如果应用程序要尝试从JarOutputStream
中的异常中恢复并重复执行相同的操作,那么由于资源泄漏,您可能会遇到严重的问题。
如果没有,那么......这并不重要。
另一个问题是编码此代码的最佳方法是什么。我的偏好是这样写:
File f = new File("myinput.txt");
try (FileOutputStream fo = new FileOutputStream(f);
JarOutputStream jo = new JarOutputStream(fo)) {
// write stuff to jo
} catch(IOException ex) {
// diagnose errors
}
但是,上面的代码将JarOutputStream
“限制”到try块。如果你真的需要在块之外使用流对象(例如,因为你要返回它),那么try-with-resources也无济于事。您需要明确地将其编码为FileOutputStream
。
答案 1 :(得分:1)
是的,您可能有泄漏,因为调用JarOutputStream的构造函数时,流对象链接到您的文件
JarOutputStream jo = null;
FileOutputStream myOut = null;
try
{
myOut = new FileOutputStream(new File("myinput.txt"));
jo = new JarOutputStream(myOut);
}
catch(IOException ex){
}
finally
{
try {
if(jo!=null)
jo.close();
if(myOut!=null)
myOut.close();
} catch (IOException e) {
}
}
答案 2 :(得分:0)
是的,这绝对是一种不好的做法,因为它可能导致泄漏。
作为一般规则,每个 closeable 资源都应该打开一个try-with-resources语句。此外,它使代码更具可读性:
try (OutputStream out=new FileOutputStream(file))
{
try (JarOutputStream jo=new JarOutputStream(out))
{
...
}
// optional catches...
}
// optional catches...
另外,请记住catch
子句不应为空(可能会隐藏执行错误)。
答案 3 :(得分:0)
你回答了自己的问题:
jo = new JarOutputStream(new FileOutputStream(f));
等于
fos = new FileOutputStream(f);
jo = new JarOutputStream(fos); //if this throws exception, fos is never closed
要解决此问题,您可以:
将try块包装到另一个中,这可能会非常难看。如果您坚持使用下一个想法不可用的Java版本,我建议不要将您的代码重写为“完全”安全,除非确实有必要(您始终打开大量资源和程序)如果他们没有关闭,那么这么长时间真的很重要。)
或者您可以使用自{7}以来可用的try-with-resources :
File f = new File ("foo");
try(FileOutputStream fos = new FileOutputStream (f);
JarOutputStream jos = new JarOutputStream (fos)) {
//do sth
} catch (IOException e) {
//log exception, etc.
}
这将使代码执行后两个流都自动关闭,此外它比手工制作的最终代码更好。