It’s called garbage collection, not resource collection!
Java’s garbage collector has made life so easy for us developers that we sometimes confuse between deleting a reference, i.e. a task the GC does, and releasing a resource – a task the GC doesn’t do. That’s because the GC does something else for us called object finalization, where resources usually clean themselves up.
When I say resources, just think of input/output streams, readers/writers, channels, JDBC, JMS.. the list could go on and on. I almost expect to see code such as:
void copy(String source, String target) { FileInputStream fis = new FileInputStream(source); FileOutputStream fos = new FileOutputStream(target); // do the copying }
But wait! Where’s the close() call?! It should actually look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | void copy(String source, String target) { FileInputStream fis = null; FileOutputStream fos = null; try { fis = new FileInputStream(source); fos = new FileOutputStream(target); // do the copying } finally { if (fis != null) { try { fis.close(); } catch (IOException) { // do nothing. } } if (fos != null) { try { fos.close(); } catch (IOException) { // do nothing. } } } } |
Not as pretty, but the resources are closed at the end of it! Notice the usage of finally to ensure that the resources are closed regardless of thrown exceptions. Also notice how each close has its own try-catch block; this is to ensure that even if the first resource wasn’t closed properly, the second one will get its chance.
Closeable objects
For some odd reason, J2SE 5.0 introduced the Closeable interface, which defines the “close” method. I say oddly, because one would expect something would have been done with it. Maybe static analysis in the compiler via a flag, perhaps an automatic closing system, maybe a new keyword to handle Closeable objects like the using keyword in .NET. Nothing of that, though. Not in J2SE 5.0, nothing in Java SE 6, and JDBC and JMS are stuck with their own exception types (which do not extend IOException) so they didn’t even get a maintenance version to make their interfaces Closeable too!
Neverthelss, it does allow removing some of the boiler plate code. Consider the following lines of code from the previous example:
9 10 11 12 13 14 15 | if (fis != null) { try { fis.close(); } catch (IOException) { // do nothing. } } |
These seem pretty generic for any Closeable object. We could easily create a utility method close(Closeable c) which works for any Closeable, reducing quite a lot of redundant code!
Automatically closing pool
Named after NeXTStep/Cocoa’s NSAutoreleasePool class, I created a small utility class which allows you to register Closeable objects to it, and then close all of them together – as the pool is Closeable too!
If you’re lazy, it uses the PhantomReference technique I describe elsewhere to close all your objects when it is garbage-collected. This way there will be less overload on the finalization queue by shortening its work, as the pool will close all the objects itself outside of the GC threads. Notice, though: It is not a good practice to leave the AutoclosePool “open”; you should always close it, just like any resource! It just knows how to take care of itself if you don’t.
With AutoclosePool the previous example code looks like the following:
1 2 3 4 5 6 7 8 9 10 | void copy(String source, String target) { AutoclosePool pool = new AutoclosePool(); try { FileInputStream fis = pool.use(new FileInputStream(source)); FileOutputStream fos = pool.use(new FileOutputStream(target)); // do the copying } finally { pool.close(); // notice that the pool doesn't throw IOException. } } |
Some points for thought
- I mentioned that the
finalizemethod closes the resource, and it’s not always true. In some cases, you have to close the resource yourself or it will never be freed. This could be true for object pools (I certainly remember a version of DBCP that worked like this, but it might be slightly more automatic now) or implementations that use JNI and rely on the user to close the resource themselves for reasons starting from negligence towards some smartass design. - I also mentioned that JMS and JDBC are stuck with their own exception types, but it’s not all true: they could still implement the interface, and ignore the directive to throw that exception. It’s ugly as hell, but it would work and let Connection, Statement, Session, Queue and more classes join the closeable party..
- I can see advantages to using the AutoclosePool technique when you have a lot of closeable objects – NIO is a classic example where you might have two or more Channels open at the same time. Instead of having to worry about closing each and every one of the channels, just
use()them and let the pool close them at the end of the method, regardless of how many of them you have added or removed while writing the method. - Update: since it came up in comments often, I’m mentioning it here as well. Notice the comment next to AutoclosePool’s
closemethod. It should disturb some of you that the class “swallows” exceptions. However, there are two good reasons for it: first, since it usesPhantomReferences to close other AutoclosePools in itsclose,useor constructor, the exception thrown might not belong to the current AutoclosePool but to another’s. Second, as Guillaume mentions in the comments as well, throwing an exception from afinallyclause is a bad habit as it could over-shadow an exception thrown from yourtryclause. In addition to all that, I implemented the ability to set anExceptionHandlerto the AutoclosePool, so that when an exception occurs it can handle it within the context of the exception instead of the context of callinguseor whatever.
I’d love to hear comments about this, so please! Go ahead!
August 4th, 2009 at 12:37 am
In the absence of something like AutoclosePool I would write the original method thusly:
void copy(String source, String target) throws IOException {
InputStream is = new FileInputStream(source);
try {
OutputStream os = new FileOutputStream(target);
try {
// do the copying
} finally {
os.close();
}
} finally {
is.close();
}
}
Note the use of the nested finally blocks; this guarantees that everything always gets closed, without null checks. (It is even a bit safer, in case fis.close() threw some RuntimeException.) The downside is deeper indentation, I guess.
Note also that opening streams and working with them can usually throw IOException, so there is no need to catch it when closing. Better to have the exception be thrown and properly reported than ignored (meaning something might be very wrong and you don’t know it). IMHO AutoclosePool.close() should be declared to throw IOException; it could collect any IOException’s coming from the pool’s members and either arbitrarily pick one to rethrow at the end, or (if you cared a lot about diagnostics) stack them together using Throwable.initCause.
August 4th, 2009 at 5:54 am
@Jesse: Originally the AutoclosePool did gather the exceptions and threw the last IOException or last RuntimeException (it gathered both).
However, I changed this for a certain reason. First, since it uses the PhantomReference trick, it means that within normal operations such as creating a new
AutoclosePool,use()ing a resource orclose()ing a pool it would clean previously unclosed pools. This allows for the pool to be safely discarded if forgotten.However, it also meant that
close()doesn’t guarantee that the exceptions thrown are your exceptions and not some other pool’s exceptions. This could be mended of course, but because of the rest of the behavior, I thought it would be easier to just hide the exceptions altogether.To solve this, I did add an optional
ExceptionHandlerwhich receives the exceptions when they occur; this way, whenever an exception does occur it would be notifying the application in the correct context (a handler’s context).Do you think a different design is preferred?
August 4th, 2009 at 5:59 am
@Jesse: To respond to the other part of your comment, I do agree I could’ve rethrown the IOExceptions, and usually I do, except in the
finallyclause since I want all the resources to close. I admit I didn’t know of the “multiple-finally” technique, but you have to admit it’s dead-ugly!August 4th, 2009 at 9:02 pm
The problem with throwing the exception from the close in the finally is that it can hide a more important exception thrown in the try block. If there’s an exception both in the try block and the finally block, it’s the one from the finally that is thrown.
August 5th, 2009 at 7:44 am
@Guillaume: I agree. I don’t know why it slipped in my mind in my answer..
Anyway, since the “exception swallowing” came up a few times I added the discussion in the comments to the post itself as an update.
Thanks!
August 21st, 2009 at 8:14 pm
I ended up using a bunch of wrappers to the JDBC classes, implementing the closeable Interface.
August 21st, 2009 at 11:57 pm
@Chronos: Did you use some sort of generic method for closing Closeables? If so, which?
April 5th, 2010 at 6:13 pm
findAverage = sum/no. of students
successRate = no. of passed / no. of students *100
Save them in the output file.