views:

672

answers:

4

In Java, is there an elegant way to detect if an exception occured prior to running the finally block? When dealing with "close()" statements, it's common to need exception handling within the finally block. Ideally, we'd want to maintain both exceptions and propogate them up (as both of them may contain useful information). The only way I can think of to do this is to have a variable outside the try-catch-finally scope to save a reference to a thrown exception. Then propogate the "saved" exception up with any that occur in the finally block.

Is there a more elegant way of doing this? Perhaps an API call that will reveal this?

Here's some rough code of what I'm talking about:

Throwable t = null; 
try {   
   stream.write(buffer); 
} catch(IOException e) {
    t = e;   //Need to save this exception for finally
    throw e;
} finally {   
    try {
       stream.close();   //may throw exception
   } catch(IOException e) {
      //Is there something better than saving the exception from the exception block?
      if(t!=null) {
         //propogate the read exception as the "cause"--not great, but you see what I mean.
         throw new IOException("Could not close in finally block: " + e.getMessage(),t);
      } else {
         throw e;  //just pass it up
      }    
   }//end close
}

Obivously, there are a number of other similar kludges that might involve saving the exception as an member variable, returning it from a method, etc... but I'm looking for something a bit more elegant.

Maybe something like Thread.getPendingException() or something similar? For that matter, is there an elegant solution in other languages?

This question actually spawned from comments in another question that raised an interesting question.

+1  A: 

You could always set a boolean flag in your catch(es). I don't know of any "slick" way to do it, but then I'm more of a .Net guy.

Joel Coehoorn
Is there a way to do it in .NET that's more "slick"?
James Schek
If I knew one, I would have mentioned it.
Joel Coehoorn
I think that's the only way to do it in .NET as well.
Scott Dorman
+6  A: 

James,

Your idea about setting a variable outside the scope of the try/catch/finally is correct. There cannot be more than one exception propagating at once.

Jeremy Ross
+2  A: 

Use logging...

try {   
   stream.write(buffer); 
} catch(IOException ex) {
    if (LOG.isErrorEnabled()) { // You can use log level whatever you want
        LOG.error("Something wrong: " + ex.getMessage(), ex);
    }
    throw ex;
} finally {   
    if (stream != null) {
        try {
            stream.close();
        } catch (IOException ex) {
            if (LOG.isWarnEnabled()) {
                LOG.warn("Could not close in finally block", ex);
            }
        }
    }
}
gedevan
+1  A: 

Instead of using a Boolean flag, I would store a reference to the Exception object. That way, you not only have a way to check whether an exception occurred (the object will be null if no exception occurred), but you'll also have access to the exception object itself in your finally block if an exception did occur. You just have to remember to set the error object in all your catch blocks (iff rethrowing the error).

I think this is a missing C# language feature that should be added. The finally block should support a reference to the base Exception class similar to how the catch block supports it, so that a reference to the propagating exception is available to the finally block. This would be an easy task for the compiler, saving us the work of manually creating a local Exception variable and remembering to manually set its value before re-throwing an error, as well as preventing us from making the mistake of setting the Exception variable when not re-throwing an error (remember, it's only the uncaught exceptions we want to make visible to the finally block).

finally (Exception main_exception)
{
    try
    {
        //cleanup that may throw an error (absolutely unpredictably)
    }
    catch (Exception err)
    {
        //Instead of throwing another error,
        //just add data to main exception mentioning that an error occurred in the finally block!
        main_exception.Data.Add( "finally_error", err );
        //main exception propagates from finally block normally, with additional data
    }
}

As demonstrated above... the reason that I'd like the exception available in the finally block, is that if my finally block did catch an exception of its own, then instead of overwriting the main exception by throwing a new error (bad) or just ignoring the error (also bad), it could add the error as additional data to the original error.

Triynko