Propagating Exceptions
Jakob Jenkov |
When an exception is thrown it is propagated up the call stack until some try-catch block finally handles it. Propagation can be either passive or active.
Passive Propagation
Passive propagation means that you just let the exception pass up the call stack without catching it. For this to be possible the exception must of course be declared by the method propagating it, or the exception must be unchecked.
Here is an example of passive prograpation:
public void doSomething() throws SomeException { try{ doSomethingThatCanThrowException(); } finally { //clean up � close open resources etc. } }
Active Propagation
Active propagation means that you catch the exception and rethrow it, or wrap it in a new exception. You will typically use active propagation when you need to add extra information to the exception, about what actions were attempted and with what data, when the exception occurred. This extra information is, as mentioned in an earlier text, called the exception context � the context the exception occurred in.
Here is an example of active propagation.
public void doSomething() throws SomeException{ try{ doSomethingThatCanThrowException(); } catch (SomeException e){ e.addContextInformation(�more info�); throw e; //throw e, or wrap it � see next line. //throw new WrappingException(e, �more information�); } finally { //clean up � close open resources etc. } }
Adding Context Information
As I explained in the text Error Location and Context, the context in which an exception occurs may be just as important as the location of the exception itself. A given location in the application may be reachable via different execution paths, and the execution path may influence the severity and cause of the error, if it occurs.
If you need to add context information to an exception as you propagate it up the call stack, you need to use active propagation. In other words, you need to catch the exception in various relevant locations on the way up the call stack, and add the relevant context information to it, before rethrowing or wrapping it.
Rethrowing vs. Wrapping Exceptions
As mentioned ealier active propagation can be implemented by either rethrowing the original exception or wrapping it in a new exception. Personally, I prefer to rethrow the existing exception, but this is not always the smartest choice.
This illustration shows how I prefer to wrap alien exceptions, and rethrow application specific exceptions:
Wrapping exceptions in checked exceptions and rethrowing them. |
The above diagram assumes that you are using checked exceptions in your application.
When an exception is caught which is an alien exception, it is wrapped in an application specific exception. This is signalled by the "wrap" arrows.
If higher layers catches an application specific exception, they just rethrow it, possibly adding information to it. Or they may just propagate it passively, without touching it. This is signalled by the "rethrow" arrow.
If your application uses unchecked exceptions, here is how the wrapping and rethrowing could look:
Wrapping exceptions in unchecked exceptions and rethrowing them. |
All alien exceptions are again wrapped in your own application specific exception. Also, if you have any old checked "legacy" exceptions you cannot just convert directly to your unchecked application specific exception already when it is thrown, wrap those too.
Once wrapped in your application specific exception, this exception is again propagated either passively or actively up the call stack, until a point where you can react to it sensibly.
Wrap Alien Exceptions
An "alien" exception is an exception thrown by a Java API or a third party library. In other words, an exception you do not control.
I prefer to catch all alien exceptions and wrap them in an appropriate application specific exception. Once the alien exception is converted to your own exception, you can propagate that exception any way you like.
Rethrowing Checked Exceptions can get Messy
If your application uses checked exceptions, rethrowing the original exception means that the method rethrowing it must also declare it. The closer you get to the top of the call hierarchy, the more exceptions will be declared thrown. Unless you just declare all your methods to throw Exception. However, if you do so you might as well use unchecked exceptions, since you are not really getting any benefit from the compiler exception checking anyways.
This is why I prefer to catch non-application specific exceptions and wrap them in an application specific exception, before propagating them up the call stack.
Rethrowing Unchecked Exceptions is Easier
Rethrowing the original exception is a bit easier when using unchecked exceptions, because you do not need to declare them all the way up the call hierarchy. However, I still prefer to catch �alien� exceptions and wrap them in application specific exceptions. In fact, you may even be forced to do so for checked �alien� exceptions, thus converting the checked alien exception into an unchecked application specific exception.
Tweet | |
Jakob Jenkov |