5

这个问题分为两部分:

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();
        }
    }

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

感谢您提供任何见解(或编辑)。

4

3 回答 3

7

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

是的,它更简洁。你对对象做的更少——重要的是,你没有做你应该做的事情。采用快捷方式通常会产生更少的代码,但是通过让文件句柄处于打开状态等待终结器关闭事物,您会发现您将获得难以可靠重现的异常。

两者之间有内存差异吗?

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

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

同样,可能无关紧要。正确性更为重要。

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

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

编辑:正如 JB Nizet 的回答中所述,您使用的代码可能已经关闭了底层流 - 这取决于是什么FileCopyUtils。如果是春季班,那没关系。如果是别的东西,你可能不是。您应该阅读文档。不过,一般原则如上所述:您应该确保某些东西关闭了流。不要仅仅因为在这种情况下您不需要明确地关闭事物,就认为在一般情况下是正确的。

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

于 2013-05-22T22:18:23.290 回答
4

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

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

(强调我的)

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

如果不是这种情况,您将不得不关闭 Reader,最好使用 Java 7 的try with resources

请注意,您的第二个示例关闭了流,但不必:关闭阅读器会自动关闭它。另请注意,如果第一个读取器无法关闭并引发 IOException,则第二个读取器将无法正确关闭。另一个使用try with resources的好理由,可以保证关闭所有内容。

于 2013-05-22T22:22:23.383 回答
1

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

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

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

于 2013-05-22T22:18:33.700 回答