This is probably a broad question, not quite SO style, but I’d still like to get some hints or guidelines if possible.
I’ve been looking through some legacy code and found a part of it that has methods with exceptions nested 3 or 4 levels down.
Is this considered to be a normal practice or should one avoid such codestyle where possible? If it should be avoided, what are the negative effects besides the increasing costs of exception handling and decreasing readability? Are there common ways of refactoring the code to avoid this?
I personally prefer the following ideology
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.
Its better 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.
Guidelines For Wrapping : 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.