OutputStream对象(在方法调用中创建为表达式,但未分配给变量)是否仍应关闭?

时间:2015-02-18 18:05:04

标签: java garbage-collection fileoutputstream

我试图匿名使用FileOutputStream来存储带有java.util.Property存储方法的属性。

Properties p = new Properties();
. . .
p.store(new FileOutputStream("nameOfFile"), "Created by me.");

读取store方法的javadoc,它表示流将被刷新并在方法返回后保持打开状态。

我想知道流会发生什么。由于我是匿名实例化的,我假设对象将立即被垃圾收集(如果这是错误的,请纠正我)。然而,当我完成它们时,我被教导要始终关闭我的溪流。在这种情况下,我无法关闭流,因为我没有对象引用它。我是否需要担心流在这里打开,或者在这种情况下Java是否通过立即收集对象来适当地处理它?<​​/ p>

3 个答案:

答案 0 :(得分:4)

这不是匿名对象(或者更确切地说是匿名类)。它只是一个未分配的对象实例化。

创建它并将其传递给store之后会有一个对它的引用,因此它不是GC'd。一旦store返回该引用消失,但您仍应跟踪该变量并在store返回后将其丢弃。只需以相同的标准方式处理所有资源并在完成后调用close更安全,这有助于在某些finalize方法调用{{1}时避免大量资源泄漏错误其他人不这样做,也避免了由于非确定性GC引起的问题。

您还不知道未来版本中的终结器实现可能会发生什么变化,因此始终调用close是最佳做法。

try-with-resources块(Java Tutorials > The try-with-resources statement)非常适用于此:

close

该块与任何(可能是多个)Properties p = new Properties(); try (FileOutputStream stm = new FileOutputStream("nameOfFile")) { p.store(stm, "Created by me."); } catch (IOException e) { // TODO: handle this } 一起使用时,会在最后调用Autocloseable并很好地处理close上的异常或正文和异常中的异常close也是如此。如果正文和close抛出异常,则会重新抛出正文异常,close可以通过close获得异常。

如果您使用其中一个块,则不应自己调用Autocloseable.close(),因为该方法不是无效的 - 调用它两次可能会产生第二次副作用。如果您有e.getSuppressed(),那么您可以安全地多次调用它。来自文档:

  

请注意,与Closeable的close方法不同,此close方法不需要是幂等的

在Java 6或更低版本中,您必须执行自己的异常处理语句,这很难,因为您必须处理您的正文和Closeable都抛出异常的情况。

答案 1 :(得分:2)

垃圾收集通常不包括开放文件或流等资源,除非finalize方法显式关闭对象的底层资源。

检查finalize FileOutputStream的代码,似乎确保调用了close

/**
 * Cleans up the connection to the file, and ensures that the
 * <code>close</code> method of this file output stream is
 * called when there are no more references to this stream.
 *
 * @exception  IOException  if an I/O error occurs.
 * @see        java.io.FileInputStream#close()
 */
protected void finalize() throws IOException {
    if (fd != null) {
        if (fd == FileDescriptor.out || fd == FileDescriptor.err) {
            flush();
        } else {

            /*
             * Finalizer should not release the FileDescriptor if another
             * stream is still using it. If the user directly invokes
             * close() then the FileDescriptor is also released.
             */
            runningFinalize.set(Boolean.TRUE);
            try {
                close();
            } finally {
                runningFinalize.set(Boolean.FALSE);
            }
        }
    }
}

但是,始终手动或在try-with-resources语句中关闭资源总是更好,因为并非所有流对象都可能在被取消引用时关闭,并且即使他们确定最终确定也不能保证按照预期发生:

try(FileOutputStream outStream = new FileOutputStream("nameOfFile")) {
     Properties p = new Properties();
     . . .
     p.store(outStream, "Created by me.");
}

答案 2 :(得分:0)

创建一个对象......

FileOutputStream fos = new FileOutputStream("nameOfFile")

然后使用它......

p.store(fos, "Created by me.");

最后关闭它。

Properties.store()命令不保留对流的引用,因此没有对它的引用,因此在方法返回后它将是GC,因为它是流范围的范围。 / p>