级联I / O流是一种不好的做法吗?

时间:2015-07-27 10:16:04

标签: java

以下代码是否会导致资源泄漏?

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已经构建了吗?

4 个答案:

答案 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.
}

这将使代码执行后两个流都自动关闭,此外它比手工制作的最终代码更好。