Is inline created InputStream closed automatically by GC?

ぃ、小莉子 提交于 2021-01-28 07:35:31

问题


I've found several similar questions, but I still can't find the answer to my question.

I know that it is enough to close the outer stream and it will close inner stream which is created in line.

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

Consider next example

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

Should the FileInputStream be assigned to a variable and then closed explicitly (or with try-with-resource construction) or will Java GC close it automatically right after props.load() method invocation, because there is no reference to the resource?


回答1:


The Javadoc states that

The specified stream remains open after this method returns.

So yes, you should close it yourself if you want to write clean code. The GC will close it eventually, if it gets around to calling the finalize() method (shown below) on the stream, but you shouldn't rely on that.

Always close your resources, that's the only way to be sure.

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



回答2:


It must be emphasized that using code like

BufferedInputStream br = new BufferedInputStream(new FileInputStream(file));
// you likely insert actual operations on br here
br.close();

is strongly discouraged, as the closing will not happen, if an operation between the stream construction and the close() call throws an exception.

You should use the “try with resource” construct instead:

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

This ensures that close() will be called even if an exception occurs in the try body. However, this code relies on the known fact that the BufferedInputStream’s close() method will call the FileInputStream’s close() method, but this does not happen until the construction of the BufferedInputStream has been completed. If the BufferedInputStream’s constructor throws an exception, it’s close() method will not be called, as there is no object to call close() on.

A really safe solution is

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

which closes the FileInputStream even if the constructor of BufferedInputStream throws an exception. That might look like a rare corner case here, as the only thing which can go wrong in that constructor would be the buffer allocation which could throw an OutOfMemoryError and you are in deep trouble anyway in that case.

But consider an example like

try(FileInputStream   fis = new FileInputStream(file);
    ObjectInputStream ois = new ObjectInputStream(fis)) {
    // your actual operations on ois here
}

Since the constructor of ObjectInputStream already reads the header, IOExceptions may be thrown, also, the header might be invalid, which would also cause an exception. Hence, there’s a lot more which can go wrong and ensuring that the underlying FileInputStream is properly closed even in these cases is much more important.



来源:https://stackoverflow.com/questions/45456509/is-inline-created-inputstream-closed-automatically-by-gc

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!