3

I have some code which creates a JarFile and a URLClassLoader, both of which I want to close at the end. Naturally, I decided to use the finally block to deal with the cleanup:

JarFile jar = ...;
URLClassLoader loader = ...;
try {
    // work ...
} finally {
    jar.close();
    loader.close();
}

However, both close() invocations can throw an exception, so if jar.close() would throw an exception, then loader.close() would not be reached. One way I thought about working around this is by surrounding jar.close() with a try-catch block:

JarFile jar = ...;
URLClassLoader loader = ...;
try {
    // work ...
} finally {
    try {
        jar.close();
    } catch(IOException e) {
    } 
    loader.close();
}

But this seems ugly and excessive. Is there an elegant way of dealing with cleanup-related exceptions in finally blocks?

Martin Tuskevicius
  • 2,590
  • 4
  • 29
  • 46

3 Answers3

6

In Java 7 and beyond, there is try with resources which handles Closeable objects.

Reformat your code thusly,

try(JarFile jar = ....; URLClassLoader loader = ....;) 
{
    // work ...
}

Only classes that implement the Closeable interface will work in this fashion, both of these classes meet this criteria.

Patrick J Abare II
  • 1,129
  • 1
  • 10
  • 31
  • Nice nice, I tend to miss those "new" features. Seems like I will refactor some code in an active project :) – MalaKa Jun 06 '15 at 16:06
  • Yeah, I really liked this feature, I always used a method `closeQuietly(Closeable... closeable)` to accomplish the same thing as Dici's answer, but allowed for a single call before. – Patrick J Abare II Jun 06 '15 at 16:08
3

Of course there is a way to encapsulate this, it is called a method ! For example, you can create a class IOUtils as the following :

public class IOUtils {
    // this class is not meant to be instantiated
    private IOUtils() { }

    public static void closeQuietly(Closeable c) {      
       if (c == null) return;
       try {
          c.close();
       } catch (IOException e) { }
    }
}

And then,

JarFile jar = ...;
URLClassLoader loader = ...;
try {
    // work ...
} finally {
    closeQuietly(jar);
    loader.close();
}

As Patrick J Abae II told it, you can also use a try-catch with resources, but you can't always do that, for example if you first create an InputStream in a try-catch, and then create several different kinds of InputStream by encapsulating the first one (ex : encapsulate in a CipherInputStream to decipher the data and then write to a FileOutputStream). Yet, I'm not saying the try-catch with resources is not a useful construct, it is enough in most cases.

Dici
  • 25,226
  • 7
  • 41
  • 82
2

Use try-with-resources:

    try (JarFile jar = new JarFile(filename);
            URLClassLoader loader = URLClassLoader.newInstance(urls)) {
        // do stuff
    } catch (IOException ex) {
        // handle ex           
    }