This question already has an answer here:
Note: This question and most of its answers date to before the release of Java 7. Java 7 provides Automatic Resource Management functionality for doing this easilly. If you are using Java 7 or later you should advance to the answer of Ross Johnson.
What is considered the best, most comprehensive way to close nested streams in Java? For example, consider the setup:
FileOutputStream fos = new FileOutputStream(...)
BufferedOS bos = new BufferedOS(fos);
ObjectOutputStream oos = new ObjectOutputStream(bos);
I understand the close operation needs to be insured (probably by using a finally clause). What I wonder about is, is it necessary to explicitly make sure the nested streams are closed, or is it enough to just make sure to close the outer stream (oos)?
One thing I notice, at least dealing with this specific example, is that the inner streams only seem to throw FileNotFoundExceptions. Which would seem to imply that there's not technically a need to worry about closing them if they fail.
Here's what a colleague wrote:
Technically, if it were implemented right, closing the outermost stream (oos) should be enough. But the implementation seems flawed.
Example: BufferedOutputStream inherits close() from FilterOutputStream, which defines it as:
155 public void close() throws IOException {
156 try {
157 flush();
158 } catch (IOException ignored) {
159 }
160 out.close();
161 }
However, if flush() throws a runtime exception for some reason, then out.close() will never be called. So it seems "safest" (but ugly) to mostly worry about closing FOS, which is keeping the file open.
What is considered to be the hands-down best, when-you-absolutely-need-to-be-sure, approach to closing nested streams?
And are there any official Java/Sun docs that deal with this in fine detail?
When closing chained streams, you only need to close the outermost stream. Any errors will be propagated up the chain and be caught.
Refer to Java I/O Streams for details.
To address the issueThis isn't right. After you catch and ignore that exception, execution will pick back up after the catch block and the
out.close()
statement will be executed.Your colleague makes a good point about the RuntimeException. If you absolutely need the stream to be closed, you can always try to close each one individually, from the outside in, stopping at the first exception.
Sun's JavaDocs include
RuntimeException
s in their documentation, as shown by InputStream's read(byte[], int, int) method; documented as throwing NullPointerException and IndexOutOfBoundsException.FilterOutputStream's flush() is only documented as throwing IOException, thus it doesn't actually throw any
RuntimeException
s. Any that could be thrown would most likely be wrapped in anIIOException
.It could still throw an
Error
, but there's not much you can do about those; Sun recommends that you don't try to catch them.The Java SE 7 try-with-resources doesn't seem to be mentioned. It eliminates needing to explicitly do a close completely, and I quite like the idea.
Unfortunately, for Android development this sweet only becomes available by using Android Studio (I think) and targeting Kitkat and above.
The colleague raises an interesting point, and there are grounds for arguing either way.
Personally, I would ignore the
RuntimeException
, because an unchecked exception signifies a bug in the program. If the program is incorrect, fix it. You can't "handle" a bad program at runtime.It is a good practice to use Apache Commons to handle IO related objects.
In the
finally
clause useIOUtils
IOUtils.closeQuietly(bWriter); IOUtils.closeQuietly(oWritter);
Code snippet below.
This is a surprisingly awkward question. (Even assuming the
acquire; try { use; } finally { release; }
code is correct.)If the construction of the decorator fails, then you wont be closing the underlying stream. Therefore you do need to close the underlying stream explicitly, whether in the finally after use or, more diifcult after successfully handing over the resource to the decorator).
If an exception causes execution to fail, do you really want to flush?
Some decorators actually have resources themselves. The current Sun implementation of
ZipInputStream
for instance has non-Java heap memory allocated.It has been claimed that (IIRC) two thirds of the resources uses in the Java library are implemented in a clearly incorrect manner.
Whilst
BufferedOutputStream
closes even on anIOException
fromflush
,BufferedWriter
closes correctly.My advice: Close resources as directly as possible and don't let them taint other code. OTOH, you can spend too much time on this issue - if
OutOfMemoryError
is thrown it's nice to behave nicely, but other aspects of your program are probably a higher priority and library code is probably broken in this situation anyway. But I'd always write:(Look: No catch!)
And perhaps use the Execute Around idiom.