Resource leak: 'in' is never closed, though it IS closed

theV0ID picture theV0ID · Jan 10, 2013 · Viewed 10.2k times · Source

I know that there are a couple of similarly entitled questions out there, but most of them have simply forgotten to put a close() directive on their stream. This here is different.

Lets say I have the following minimal example:

public void test() throws IOException
{
    InputStream in;
    if( file.exists() )
    {
        in = new FileInputStream( file );
    }
    else
    {
        in = new URL( "some url" ).openStream();
    }
    in.close();
}

This give me a Resource leak: 'in' is never closed warning in Eclipse (Juno SR1). But when I move the in.close() into the conditional block, the warnings vanishes:

public void test() throws IOException
{
    InputStream in;
    if( file.exists() )
    {
        in = new GZIPInputStream( new FileInputStream( file ) );
        in.close();
    }
    else
    {
        in = new URL( "some URL" ).openStream();
    }
}

What is going on here?

Answer

Dave G picture Dave G · Jan 10, 2013

Because of the IO exception, you can run into a resource leak (poentially)

Try doing the following:

public void test() throws IOException
{
    InputStream in= null;
    try {
        if( file.exists() )
        {
            // In this case, if the FileInputStream call does not
            // throw a FileNotFoundException (descendant of IOException)
            // it will create the input stream which you are wrapping
            // in a GZIPInputStream (no IO exception on construction)
            in = new GZIPInputStream( new FileInputStream( file ) );
        }
        else
        {
            // Here however, if you are able to create the URL
            // object, "some url" is a valid URL, when you call
            // openStream() you have the potential of creating
            // the input stream. new URL(String spec) will throw
            // a MalformedURLException which is also a descendant of
            // IOException.
            in = new URL( "some url" ).openStream();
        }

        // Do work on the 'in' here 
    } finally {
        if( null != in ) {
            try 
            {
                in.close();
            } catch(IOException ex) {
                // log or fail if you like
            }
        }
    }
}

Doing the above will make sure you've closed the stream or at least made a best effort to do so.

In your original code, you had the InputStream declared but never initialized. That is bad form to begin with. Initialize that to null as I illustrated above. My feeling, and I'm not running Juno at the moment, is that it sees that the InputStream 'in', may potentially make it through all the hoops and hurdles to get to the point at which you are going to use it. Unfortunate, as someone pointed out, your code is a bit dodgy for an example. Doing this as I've detailed as well as @duffymo you'll get rid of the warning.