Common Java Cookbook

Edition: 0.19

Download PDF or Read on Scribd

Download Examples (ZIP)

10.3. Closing Streams, Readers, and Writers

10.3.1. Problem

You need to close an InputStream, OutputStream, Reader, or Writer, and you want to avoid catching an IOException in a finally block.

10.3.2. Solution

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 );
}

10.3.3. Discussion

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.

10.3.4. See Also

This recipe used CopyUtils, which was demonstrated in Recipe 10.2.


Creative Commons License
Common Java Cookbook by Tim O'Brien is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 United States License.
Permissions beyond the scope of this license may be available at http://www.discursive.com/books/cjcook/reference/jakartackbk-PREFACE-1.html. Copyright 2009. Common Java Cookbook Chunked HTML Output. Some Rights Reserved.