How safe is my safe rethrow?
- by gustafc
(Late edit: This question will hopefully be obsolete when Java 7 comes, because of the "final rethrow" feature which seems like it will be added.)
Quite often, I find myself in situations looking like this:
do some initialization
try {
do some work
} catch any exception {
undo initialization
rethrow exception
}
In C# you can do it like this:
InitializeStuff();
try
{
DoSomeWork();
}
catch
{
UndoInitialize();
throw;
}
For Java, there's no good substitution, and since the proposal for improved exception handling was cut from Java 7, it looks like it'll take at best several years until we get something like it. Thus, I decided to roll my own:
(Edit: Half a year later, final rethrow is back, or so it seems.)
public final class Rethrow {
private Rethrow() { throw new AssertionError("uninstantiable"); }
/** Rethrows t if it is an unchecked exception. */
public static void unchecked(Throwable t) {
if (t instanceof Error)
throw (Error) t;
if (t instanceof RuntimeException)
throw (RuntimeException) t;
}
/** Rethrows t if it is an unchecked exception or an instance of E. */
public static <E extends Exception> void instanceOrUnchecked(
Class<E> exceptionClass, Throwable t) throws E, Error,
RuntimeException {
Rethrow.unchecked(t);
if (exceptionClass.isInstance(t))
throw exceptionClass.cast(t);
}
}
Typical usage:
public void doStuff() throws SomeException {
initializeStuff();
try {
doSomeWork();
} catch (Throwable t) {
undoInitialize();
Rethrow.instanceOrUnchecked(SomeException.class, t);
// We shouldn't get past the above line as only unchecked or
// SomeException exceptions are thrown in the try block, but
// we don't want to risk swallowing an error, so:
throw new SomeException("Unexpected exception", t);
}
private void doSomeWork() throws SomeException { ... }
}
It's a bit wordy, catching Throwable is usually frowned upon, I'm not really happy at using reflection just to rethrow an exception, and I always feel a bit uneasy writing "this will not happen" comments, but in practice it works well (or seems to, at least). What I wonder is:
Do I have any flaws in my rethrow helper methods? Some corner cases I've missed? (I know that the Throwable may have been caused by something so severe that my undoInitialize will fail, but that's OK.)
Has someone already invented this? I looked at Commons Lang's ExceptionUtils but that does other things.
Edit:
finally is not the droid I'm looking for. I'm only interested to do stuff when an exception is thrown.
Yes, I know catching Throwable is a big no-no, but I think it's the lesser evil here compared to having three catch clauses (for Error, RuntimeException and SomeException, respectively) with identical code.
Note that I'm not trying to suppress any errors - the idea is that any exceptions thrown in the try block will continue to bubble up through the call stack as soon as I've rewinded a few things.