The Java I/O classes java.io.Reader
, java.io.Writer
, java.io.InputStream
, java.io.OutpuStream
and their various subclasses all have a close()
method that can throw an IOException
.
Is there any consensus on the proper way to handle such exceptions?
I have often seen recommendations to just silently ignore them, but that feels wrong, and at least in case of resources opened for writing, a problem while closing the file might mean that unflushed data could not be written/sent.
On the other hand, when reading resources, I'm totally unclear on why close()
might throw and what to do about it.
So is there any standard recommendation?
A related question is Does close ever throw an IOException?, but that is more about which implementations really do throw, not about how to handle the exceptions.
It depends on what you are closing. For example, closing a
StringWriter
does nothing. The javadocs are clear on that. In this case, you can ignore the IOException because you know that it will never be generated. Technically, you don't even need to callclose
.For other streams, log and handle the exception as appropriate.
Generally resource handling should look like this:
In (the unlikely) case of
release
throwing an exception, any exception thrown byuse
will be dropped. I don't have a problem with the exception thrown closest to the catcher winning. I believe ARM blocks in JDK7(?) will do something crazy in this case, like rethrowing theuse
exception with therelease
exception attached.If you use the Execute Around idiom, you can put these decisions and potentially messy code in one (or few) places.
Ignoring or just logging is usually a bad idea. Even though it is true that you cannot recover from it, I/O exceptions should always be handled in a unified manner to make sure your software behaves in a unified way.
I would at least suggest handling like below:
The above is pretty verbose but works well, because it will prefer the
IOException
during I/O on the resource to the one during close, since it is more likely to contain information of interest to the developer. The code will also throw anIOException
when something goes wrong, so you get a unified behaviour.There might be nicer ways of doing it, but you get the idea.
Ideally, you would create a new exception type that would allow storing sibling exceptions, so in case you get two
IOException
s you could store them both.Try to use flush before you close the writer. The main reason for exception in close is that some other resources might have been using the data or the writer/reader may not be open at all. try to find wheather the resoures is open before closing it.
First of all don't forget to put the close() inside the "finally" section of your try catch block. Second you can surround the close method with another try catch exception and log the exception.
Well, in most cases, close() doesn't actually throw an IOException. Here's the code for InputStream.java:
Errors from closing a network resource should really be of some type of
RuntimeException
, since you can disconnect a networked resource after the program connects to it.You can see some example of various implementations of Reader/Writer and Streams using Google Code Search. Neither BufferedReader nor PipedReader actually throw an IOException, so I think you're mostly in the safe by not worrying about it. If you're really worried, you can check the implementation of the libraries you're using to see if you ever need to worry about the exception.
Like others mentioned, you can't do much about the IOException other than log it.
After all,
try/catch blocks
in thefinally
clause are pretty ugly.Edit:
Further inspection reveals subclasses of
IOException
likeInterruptedIOException
,SyncFailedException
, andObjectStreamException
, along with classes that inherit from it. So just catching anIOException
would be too general -- you wouldn't know what to do with the information other than logging it because it could be from a whole range of errors.Edit 2:
Urk,
BufferedReader
was a bad example, since it takes aReader
as input. I've changed it toInputStream.java
However, there's a hierarchy with
InputStream
<=FilterInputStream
<=BufferedInputStream
<=InputStreamReader
(via inheritance and private instances) that all trickle up to theclose()
method inInputStream
.