内联创建的InputStream是否由GC自动关闭?

时间:2017-08-02 09:14:26

标签: java garbage-collection inputstream

我发现了几个类似的问题,但我仍然无法找到问题的答案。

我知道关闭外部流就足够了,它将关闭在线创建的内部流。

BufferedInputStream br = new BufferedInputStream(new FileInputStream(file));
br.close();

考虑下一个例子

Properties props = new Properties();
props.load(new FileInputStream(configPath));

是否应将FileInputStream分配给变量然后显式关闭(或使用try-with-resource构造),或者Java GC会在props.load()方法调用之后立即自动关闭它,因为没有参考资源?

2 个答案:

答案 0 :(得分:6)

Javadoc声明

  

此方法返回后,指定的流仍保持打开状态。

所以是的,如果你想编写干净的代码,你应该自己关闭它。 GC最终将关闭它,如果它可以在流上调用finalize()方法(如下所示),但是shouldn't rely on that

始终关闭您的资源,这是确定的唯一方法。

/**
 * Ensures that the <code>close</code> method of this file input stream is
 * called when there are no more references to it.
 *
 * @exception  IOException  if an I/O error occurs.
 * @see        java.io.FileInputStream#close()
 */
protected void finalize() throws IOException {
    if ((fd != null) &&  (fd != FileDescriptor.in)) {
        /* if fd is shared, the references in FileDescriptor
         * will ensure that finalizer is only called when
         * safe to do so. All references using the fd have
         * become unreachable. We can call close()
         */
        close();
    }
}

答案 1 :(得分:3)

必须强调使用像

这样的代码
BufferedInputStream br = new BufferedInputStream(new FileInputStream(file));
// you likely insert actual operations on br here
br.close();
强烈建议不要使用

,因为如果流构造和close()调用之间的操作引发异常,则不会发生关闭。

您应该使用“try with resource”构造:

try(BufferedInputStream br = new BufferedInputStream(new FileInputStream(file))) {
    // your actual operations on br here
}

这确保即使close()正文中发生异常,也会调用try。但是,此代码依赖于已知的事实,BufferedInputStream的{​​{1}}方法将调用close()的{​​{1}}方法,但这不会发生,直到构造FileInputStream已完成。如果close()的构造函数抛出异常,则不会调用BufferedInputStream方法,因为没有对象可以调用BufferedInputStream

一个非常安全的解决方案是

close()

,即使close()的构造函数抛出异常,也会关闭try(FileInputStream fis = new FileInputStream(file); BufferedInputStream br = new BufferedInputStream(fis)) { // your actual operations on br here } 。这可能看起来像是一个罕见的极端情况,因为在该构造函数中唯一可能出错的是缓冲区分配,它可能抛出FileInputStream并且在这种情况下你无论如何都会陷入深深的麻烦。

但请考虑像

这样的例子
BufferedInputStream

由于OutOfMemoryError的构造函数已经读取了标头,因此可能会抛出try(FileInputStream fis = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(fis)) { // your actual operations on ois here } ,标头也可能无效,这也会导致异常。因此,还有更多可能出错的问题,并确保即使在这些情况下基础ObjectInputStream已正确关闭也更为重要。