Note: This article applies to Java 6 and earlier versions of Java

Java 7 has introduced the try-with-resources statement which, whilst still requiring resources be closed, makes the exception handling much easier


Using the 'finally' Clause to Close IO Streams

This Q&A article attempts to explain why it is important to use the finally clause to close IO streams, although it equally applies to any objects that reserve non-memory system resources.

Why do we have to close an IO stream?

When an IO Stream is opened system resources are reserved and these resources are only released when the IO Stream is closed or garbage collected. Despite what is said on a number of sites it should never be left to the garbage collector to release reserved resources. You, as the programmer, have no control as to when the garbage collector runs or if it ever runs and you may run out of resources before it does run.

Remember, calling System.gc() does not actually run the garbage collector it is just a suggestion to the JVM that it may be appropriate to perform garbage collector. The JVM may or may not actually run the garbage collector.

So, in short, you should consider it your responsibility to close any IO Streams you open.

Why can't we just call the IO Stream's close method?

You could write the following code and you may even see code like this in examples:

public String readFile(File file) throws FileNotFoundException, IOException
    {
    BufferedReader in = new BufferedReader(new FileReader(file));
    StringBuilder text = new StringBuilder();

    // read the first line
    String line = in.readLine();

    // continue to read lines whilst they are available
    while ( line != null )
        {
        text.append(line);
        line = in.readLine();
        }

    // close the stream
    in.close();

    return text.toString();
    }
  

The problem here is that if an exception is thrown during the read loop the method will exit without closing the stream and hence without releasing the file system resources.

How do we make sure the close method is called?

If we wrap the code in a try-catch-finally statement and place the call to the close method in the finally clause we can ensure it always runs regardless of how the method exits. For example:

public String readFile(File file) throws FileNotFoundException, IOException
    {
    BufferedInputStream in = null;

    try {
        StringBuilder text = new StringBuilder();
        in = new BufferedReader(new FileReader(file));

        // read the first line
        String line = in.readLine();

        // continue to read lines whilst they are available
        while ( line != null )
            {
            text.append(line);
            line = in.readLine();
            }

        return text.toString();
        }
    finally
        {
        // close the stream
        in.close();
        }
    }
  

Now whilst this approach appears to solve the problem there is a flaw. If the creation of the input stream fails for example by throwing a FileNotFoundException then when the finally clause executes it will call the close method on 'in'. But the variable 'in' will be null and so a NullPointerException will be thrown masking the original problem and almost certainly evading any FileNotFoundExcpetion handling in the calling method.

Fortunately the answer is fairly easy, check to see if 'in' is null before trying to close it.

public String readFile(File file) throws FileNotFoundException, IOException
    {
    BufferedInputStream in = null;

    try {
        StringBuilder text = new StringBuilder();
        in = new BufferedReader(new FileReader(file));

        // read the first line
        String line = in.readLine();

        // continue to read lines whilst they are available
        while ( line != null )
            {
            text.append(line);
            line = in.readLine();
            }

        return text.toString();
        }
    finally
        {
        // close the stream
        if ( in != null )
            in.close();
        }
    }
  

This approach works well when working with a single resource, unfortunately the problem is more complicated when multiple resources are involved.

The following mistake can be seen in many examples and whilst the code initially looks correct it has a major flaw:

public static boolean compareFile(File file1, File file2) throws FileNotFoundException, IOException
    {
    BufferedInputStream in1 = null;
    BufferedInputStream in2 = null;

    try {
        in1 = new BufferedInputStream(new FileInputStream(file1));
        in2 = new BufferedInputStream(new FileInputStream(file2));

        // compare the files
        boolean result = true;
        int i1, i2;
        do  {
            i1 = in1.read();
            i2 = in2.read();
            result = (i1 == i2);
            }
        while ( result && i1 != -1 && i2 != -1);

        return result;
        }
    finally
        {
        // close the streams
        if ( in1 != null )
            in1.close();

        if ( in2 != null )
            in2.close();
        }
    }
  

The problems here is the close method can itself throw an exception and if this happens when closing the first stream, the second stream will not be closed.

So how do we make sure the second close method is always called?

The answer is simply to use another try-catch-finally statement around the first call to the close method.

public static boolean compareFile(File file1, File file2) throws FileNotFoundException, IOException
    {
    BufferedInputStream in1 = null;
    BufferedInputStream in2 = null;

    try {
        in1 = new BufferedInputStream(new FileInputStream(file1));
        in2 = new BufferedInputStream(new FileInputStream(file2));

        // compare the files
        boolean result = true;
        int i1, i2;
        do  {
            i1 = in1.read();
            i2 = in2.read();
            result = (i1 == i2);
            }
        while ( result && i1 != -1 && i2 != -1);

        return result;
        }
    finally
        {
        // close the streams
        try {
            if ( in1 != null )
                in1.close();
            }
        finally
            {
            if ( in2 != null )
                in2.close();
            }
        }
    }
  

Conclusion

The safest way to ensure resources are always released is to use try-catch-finally statements and release the resources in the finally clause.