问题
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, IOException
s 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