Ushanka

Sunday, February 3, 2008

When goodbyes aren't enough...

The Java core classes have a pretty nasty habit of throwing IOExceptions in close methods. Since IOExceptions are not derived from RuntimeException, you either have to catch them or declare them as thrown from the method calling close. Now, suppose I have a class that holds a couple of resources, r1 and r2. Let's see what happens if I try to release them together:

try
{
r1.close();
r2.close();
}
catch(IOException e)
{
// Do whatever I need to here...
}

If r1's close happens to throw, r2's close will never be called and I might (in a long-running application) leak resources. The same problem occurs if I don't bother catching the exception and declare it thrown from my method. Putting the close calls in the finally clause won't fix the problem either. A working solution could be:

try
{
r1.close();
}
catch(IOException e)
{
// Do whatever I need to here...
}
try
{
r2.close();
}
catch(IOException e)
{
// Do whatever I need to here...
}

This code looks worse than checking for return codes! What's more, I, as a programmer, am getting rid of a resource. I have decided that the given resource is no longer of any use to me. I am throwing it away. And it's coming back!

I can't think of a single reason an exception (checked or unchecked) should be thrown from a method that is releasing a resource. In situations like this, a return code should be used instead of exceptions because the programmer has, by the very act of calling your method, declared that she is no longer interested in the resource.

Labels: ,

4 Comments:

  • I understood almost everything in your blog post. However, what do you mean by, "And it's coming back!"? This sentence jarred me quite a bit, and I couldn't comprehend what you meant here.

    You write very well, by the way.

    By Blogger John "Z-Bo" Zabroski, At February 8, 2008 5:57 PM  

  • Thanks for the comment! What I mean by that is that the resource we just attempted to release is still making demands of the caller (catch IOException) after the caller has said, "You no longer exist in my eyes."

    It's not possible to just ignore the resource as soon as we call r.close(). The resource has an impact on the code after the call to close.

    By Blogger sharvil, At February 10, 2008 3:48 PM  

  • There are a number of proposals which aim to make this much easier (and safer) in a future version of Java:

    'ARM blocks' are specifically aimed at this problem. There's a prototype available here.
    'BGGA' Closures deal with this in a different way, and have a much wider scope. Follow that link for a prototype too.
    JCA takes a similar approach to BGGA, but there's no prototype of this functionality yet.

    By Blogger Mark Mahieu, At March 2, 2008 4:30 PM  

  • Thanks for those links, Mark. While ARM blocks solves the problem in the short-term by adding syntactic elements to the language, I don't think it tackles the real issue: poor API design.

    The point is that the API designer isn't thinking about the intent of the caller. Rather, the designer is (probably) thinking, "exceptions are for error reporting" and applies that blindly without considering the consequences or what the caller is implicitly telling you.

    I would be better to see closures being passed around in these scenarios. It preserves the control flow in the caller but the point still remains: handling errors on close should be optional and the API designer must be responsible enough to think about the caller's intent.

    By Blogger sharvil, At March 5, 2008 7:06 PM  

Post a Comment



Links to this post:

Create a Link

<< Home