Jeremy Stein - Journal

« »

Exceptions in the finally block

My apologies to non-programmers. Today, I have something to say about exceptions that are thrown in the finally block…

conn = new Connection(...);
try {
    // database operations
} finally {
    conn.close();
}

Now, suppose some database operation in the try block throws an exception. Before that exception is propogated to the caller, the finally block is executed. In my experience, it’s common for a failed database operation to prevent the connection from closing normally. Thus, conn.close() itself throws an exception. Which exception is received by the caller? The original exception or the close exception? Unfortunately, the close exception is propogated, masking the original exception (the only one we really care about).

So, here’s what I’ve often done in the past:

conn = new Connection(...);
try {
    // database operations
} finally {
    try {
        conn.close();
    } catch (Throwable t) {
        // Ignore it to avoid masking original exception
    }
}

And that has worked fairly well for me. However, in a recent project, we noticed that we were receiving an error closing a connection. The code was similar to the first example above, so I changed it to be like the second example, so that we could see the original exception. The result? No exception was thrown.

Uh-oh. So, in the case when nothing else goes wrong, but the connection can’t be closed, I’ve completely hidden that failure. What should I do?

Option 1: Write complicated code

conn = new Connection(...);
Throwable finallyProblem = null;
try {
    // database operations
} finally {
    try {
        conn.close();
    } catch (Throwable t) {
        finallyProblem = t;
    }
}
if (finallyProblem != null) {
    throw finallyProblem;
}

Yeah, that’s a bit excessive.

Option 2: Log it

conn = new Connection(...);
try {
    // database operations
} finally {
    try {
        conn.close();
    } catch (Throwable t) {
        log.warning(t);
    }
}

Yeah, I guess that works. But how often do you check your logs?

Option 3: Rationalize away the problem.

This is my favorite option <grin>. Stick with the code that discards the exception in the finally block. Theoretically, code that releases resources should not throw an exception. Ever. It makes it very difficult (impossible?) to create exception-safe code if you can’t make that assumption.

August 13, 2004 2 Comments.

2 Comments

  1. Bob replied:

    “Now, suppose some database operation in the try block throws an exception. Before that exception is propogated to the caller, the finally block is executed. In my experience, itÂ’s common for a failed database operation to prevent the connection from closing normally. Thus, conn.close() itself throws an exception.”

    Might be true for Java, but I’ve never had side-effects from previous exceptions prevent the closing of a connection object in the .Net/Mono framework. So it’s option #3 safe so far as I can tell. I suppose I could use Lutz Roeder’s reflector to disassemble the code and check, but I’m not nearly motivated enough. One more reason I don’t like Java? (Now if only we could get support for inner classes in .Net/Mono, then I’d be really happy.)

    September 10th, 2004 at 12:21 pm. Permalink.

  2. Jeremy replied:

    Anecdotal evidence aside, the real problem is that we need a way (in both Java and C#) to designate a function as nothrow (with compiler enforcement). Otherwise, you can never really be sure.

    September 10th, 2004 at 2:24 pm. Permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

« »