你需要关闭溪流吗?

时间:2013-05-22 22:14:43

标签: java syntax inputstream

这个问题分为两部分:

InputStream i1 = new InputStream()new InputStream()之间的区别是什么?

创建所有局部变量仅仅是为了关闭它们是否值得?

我知道简单的答案,第一个你可以保留变量,继续使用变量甚至关闭输入流就像一个优秀的程序员。第二个你失去了它的参考,但它看起来更简洁。这两者之间有什么记忆差异吗?速度差(毁灭性)怎么样?

现在举例说明了我的想法。首先,我们使用`'new Object()`而无需抛弃它。

 public void getLongStrings() throws IOException {
        try {
            foo = FileCopyUtils.copyToString(new InputStreamReader(aBook.getInputStream()));
            bar = FileCopyUtils.copyToString(new InputStreamReader(aNovel.getInputStream()));
        }
        catch (IOException ioe) {
            //do something appropriate here;
        }
    }

现在更详细的方法

public void getLongStrings() throws IOException {
        InputStream i1 = null;
        InputStream i2 = null;
        InputStreamReader isr1 = null;
        InputStreamReader isr2 = null;
        try {
            i1 = aBook.getInputStream();
            i2 = aNovel.getInputStream();
            isr1 = new InputStreamReader(i1);
            isr2 = new InputStreamReader(i2);
            foo = FileCopyUtils.copyToString(isr1);
            bar = FileCopyUtils.copyToString(isr2);
        }
        catch (IOException ioe) {
            //do something appropriate here
        } finally {
            if (i1 != null) i1.close();
            if (i2 != null) i2.close();
            if (isr1 != null) isr1.close();
            if (isr2 != null) isr2.close();
        }
    }

第一个还是第二个更好?一个比另一个快吗?即使看起来不漂亮,关闭我所有的流是否明智?

感谢您提供任何见解(或修改)。

3 个答案:

答案 0 :(得分:7)

  

第二个你失去了它的参考,但它看起来更简洁。

是的,它更简洁。你对这个对象做的很少 - 重要的是,你没有做应该做的事情。采用快捷方式通常会产生较少的代码,但是通过在终结器关闭之前保持打开文件句柄,您会发现您将获得难以可靠再现的异常。

  

两者之间是否有任何记忆差异?

也许,但那不相关。这里重要的资源不是内存,而是文件句柄。

  

速度差异(破坏中)怎么样?

再次,可能是无关紧要的。正确性更为重要。

(请注意,您当前的第二个代码仍然不完全可靠 - 如果其中一个早期close()调用引发异常,则不会关闭其余代码。)

如果您使用的是Java 7,则应该查看try-with-resources statement,这会使所有这些变得更加简单。

编辑:正如JB Nizet的回答所述,你正在使用的代码可能已经关闭了基础流 - 这取决于FileCopyUtils是什么。如果是Spring课程,你没事。如果它是其他东西,你可能不是。你应该阅读文档。一般原则如上所述:您应确保某事关闭流。不要认为只是因为在这种情况下你不需要明确地关闭事物,这在一般情况下是正确的。

请注意,GuavaInputSupplierOutputSupplier接口在这里非常有用 - 它允许您在知道输入/输出尚未打开的情况下传递供应商然而 ...这意味着其他代码可以执行打开/复制/关闭(或任何需要的)并为您处理所有...您最终不会使用代码中的任何对象< em>可以关闭。

答案 1 :(得分:4)

假设这是Spring的FileCopyUtils,its javadoc说:

  

所有复制方法使用4096字节的块大小,并在完成后关闭所有受影响的流

(强调我的)

因此,在这种情况下,您的初始方法非常好:Spring处理Reader的关闭,关闭Reader关闭包装的流。

如果不是这种情况,则必须关闭Reader,最好使用Java 7的尝试使用资源

请注意,您的第二个示例关闭了流但不必关闭:关闭阅读器会自动关闭它。另请注意,如果第一个阅读器无法关闭并抛出IOException,则第二个阅读器将无法正确关闭。使用尝试使用资源的另一个好理由是保证关闭所有内容。

答案 2 :(得分:1)

假设FileCopyUtils.copyToString() 关闭提供的流,则第二种方法更好。

必须调用

close()来释放与该流相关的任何资源。所以这不是代码漂亮或性能的问题,而是正确性。

第二种方法有一个错误,当任何close次调用抛出异常时,所有剩余的close()次调用都不会被调用。