You need to close an InputStream
, OutputStream
, Reader
, or Writer
, and you want to avoid catching an
IOException
in a finally
block.
Use IOUtils.closeQuietly()
to close an InputStream
, OutputStream
, Reader
, or Writer
without having to test for null
or deal with an IOException
. The following code demonstrates
the use of closeQuietly( )
to avoid a
nasty try
/catch
within a finally
block:
import org.apache.commons.io.IOUtils import org.apache.commons.io.CopyUtils Reader reader = null; String result = "": try { File file = new File( "test.dat" ); reader = new FileReader( file ); result = CopyUtils.toString( reader ); } catch( IOException ioe ) { System.out.println( "Unable to copy file test.dat to a String." ); } finally { IOUtils.closeQuietly( reader ); }
It is always a good idea to close streams, readers, and writers in
finally
blocks because you can
guarantee that a system will release I/O resources even if an exception
is thrown. A call to close( )
releases resources associated with the stream, but
because close( )
can throw an
IOException
, you need to either surround your call to close( )
with a try
/catch
block, or declare that your method throws an IOException
. This problem is best illustrated
by the following code, which closes a Reader
and Writer
without the help of IOUtils
:
Reader reader = null; Writer writer = null; String result = "": try { File file = ew File("test.dat"); reader = new FileReader( file ); writer = new StringWriter( ); CopyUtils.copy( reader, writer ); result = writer.toString( ); } catch( IOException ioe ) { System.out.println( "A serious problem has happened" ); } finally { try { if( reader != null ) { reader.close( ); } } catch( IOException ioe ) { System.out.println( "There has been a problem closing the reader." ); } try { if( writer != null ) { writer.close( ); } } catch( IOException ioe ) { System.out.println( "There has been a problem closing the writer." ); } }
The code within the finally
block is as tedious to read as it is to write. To avoid a NullPointerException
, both the Reader
and
Writer
need to be compared with
null
, and both Reader
and Writer
need separate try
/catch
blocks to avoid a situation where a Writer
remains open because of a problem
closing the Reader
. Another variation
on this theme is to surround the entire example with a single try
/catch
for IOException
:
try { Reader reader = null; Writer writer = null; String result = "": try { File file = new File("test.dat"); reader = new FileReader( file ); writer = new StringWriter( ); CopyUtils.copy( reader, writer ); result = writer.toString( ); } finally { if( reader != null ) { reader.close( ); } if( writer != null ) { writer.close( ); } } } catch( IOException ioe ) { System.out.println( "There was an I/O exception." ); }
While this looks manageable, the try
/catch
for IOException
has been expanded to
cover the entire example, just to avoid catching an exception in a
finally
block. In the previous
sample, when an IOException
was
thrown, the exception was handled within a few lines of its origin,
making it easier to provide meaningful context in an exception message.
Expanding the scope of a try
/catch
block and introducing a nested try
/catch
/finally
is an overly complex solution for what
should be a relatively straightforward task—closing a Reader
and a Writer
. There is a more subtle problem with
this second approach, as well; if an IOException
is thrown by reader.close( )
in the finally
block, writer.close( )
may never be executed—a
possible resource leak.
IOUtils.closeQuietly( )
allows
you to ignore this dilemma entirely if you accept the assumption that a
problem closing a stream can be safely ignored. If there is a problem
closing an InputStream
, OutputStream
, Reader
, or Writer
, it is unlikely that you will be able
to take any corrective action in a finally
block. IOUtils.closeQuietly()
takes a reference to an
InputStream
, OutputStream
, Reader
, or Writer
, tests for null
, and swallows any IOException
that may be thrown in the process of closing a
stream or reader.
This recipe used CopyUtils
,
which was demonstrated in Recipe
10.2.