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.
