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.