14

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?

svz
  • 4,356
  • 9
  • 35
  • 64

8 Answers8

16

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.

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.
    }

}
Rahul
  • 14,456
  • 3
  • 36
  • 60
3

Checked Exceptions should not be propagated up the stack or chained if possible. If a method is throwing a checked Exception its caller is supposed to handle it, if caller is not handling it and propagating it to its caller, then overall complexity increases.

In a three layered example : Dao , Service , Controller

DAO layer will throw DAOException Service layer should not expose DAOException to Controller , instead it should be throwing relevant BuinessExceptions, which the Controller should be handling.

Subin Sebastian
  • 10,367
  • 3
  • 35
  • 41
3

Exception handling tends to be an expensive way to handle flow control (certainly for C# and Java).

The runtime does quite a lot of work when an exception object is constructed - getting the stack trace together, figuring out where the exception is handled and more.

All this costs in memory and CPU resources that do not need to be expanded if flow control statements are used for flow control.

Additionally, there is a semantic issue. Exceptions are for exceptional situations, not for normal flow control. One should use exception handling for handling unanticipated/exceptional situations, not as normal program flow, because otherwise, an uncaught exception will tell you much less.

Apart from these two, there is the matter of others reading the code. Using exceptions in such a manner is not something most programmers will expect, so readability and how understandable your code is suffer. When one sees "Exception", one thinks - something bad happened, something that is not supposed to happen normally. So, using exceptions in this manner is just plain confusing.

Please take a look at below links

Exception Handling: Common Problems and Best Practice with Java 1.4 - pdf

Why not use exceptions as regular flow of control?

Best Practices for Exception Handling

Error Handling

Mr. Google Links

Community
  • 1
  • 1
Fahim Parkar
  • 28,922
  • 40
  • 153
  • 260
3

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?

This is not a necessary process to handle your exception in this way, as it will increase your application overhead, until you really need to handle very specific exception(checked or Alien Exceptions) and you can ignore overhead to get specific information to handle that exception.

If it should be avoided, what are the negative effects besides the increasing costs of exception handling and decreasing readability?

As I mentioned you will not get specific information about the exception, if you are not going to use nested exception handling(throws with some added information to the upper handler) you may/may'not do specific action on behalf of some tough exception, but in nested case you can do action by handling that specific situation.

Are there common ways of refactoring the code to avoid this?

If you have a poorly factored program that does what the you want and has no serious bugs, for god sake leave it alone! When you need to fix a bug or add a feature, you Refactor Mercilessly the code that you encounter in your efforts. Override the Exception Class in your custom Exception Handler and add some added features to handle your problem.

The overriding method must NOT throw checked exceptions that are new or broader than those declared by the overridden method. For example, a method that declares a FileNotFoundException cannot be overridden by a method that declares a SQLException, Exception, or any other non-runtime exception unless it's a subclass of FileNotFoundException.

Hop this will help you.

Puneet
  • 593
  • 5
  • 22
0

You should do away with the exception nesting. You should either avoid chaining the exceptions in the first place, or (selectively) unwrap and then rethrow the nested exceptions further up the stack.

Swapnil
  • 7,762
  • 4
  • 34
  • 56
0

About handling legacy code I would recommend you have a look at the book covering the topic: http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052 You dont even have to go through the whole book, just look at the things that concern you at the moment.

Also a good book regarding good practices is: http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882/ref=sr_1_1?s=books&ie=UTF8&qid=1356340809&sr=1-1&keywords=clean+code

The best approach when handling nested exceptions is refactoring the code and using runtime instead of checked exceptions, and handling those where needed. This way the code is more readable and easier to maintain.

Sinisha Mihajlovski
  • 1,719
  • 1
  • 18
  • 32
0

Its depend on the Business logic. You may take action on the exception there itself or you may propogate it all the way upto caller and leave it to the caller for what action he want.

e.g. There are lot of third party API where they don't handle the exception but they throw it from method and hence facilitate API users to take actions as per their need.

e.q. oracle JDBC driver. Driver.getConnection() throws exception. Now caller/API user can handle it as per their need. One may just print stack trace, one may notify admin asking for his attention or one may choose just silently exit the application.

Vallabh Patade
  • 4,570
  • 5
  • 29
  • 40
0

There are two approaches:

To generate a separate exception for each event.
To create a generic exception and describe what caused it 

The first approach allows you to write different code for handling the different events, but it requires you to write lot of Exception classes and in some case it could be just too much.

The second approach is more concise, but it makes it difficult to handle the different situations.

As it happens very often in programming the best solution is in the middle, where you balance generating separate exceptions and using one exception for other cases.

The rule of the thumb in this case could be to generate a separate Exception class for the exceptions you want to handle specifically with separate code.

Similarly to the what to throw, we should also have control on what to catch. We can use two approaches for our catch blocks:

A single catch block for all. For example:

catch (Throwable e) {
throw new CommandExecutorException(e);
}

many catch blocks one for each Exception. For example:

} catch (ClassCastException e1) {
 ...
} catch (FileNotFoundException e) {
... 
} catch (IOException e) {
...
}

The first approach is very compact but basically groups every exception in the same case, it's useful only in the situation where all the exceptions are managed equally and do the same thing. This approach is generally discouraged as it gives no control on the exceptions being catched, leading sometimes to tough bugs, which are also hard to find.

The second approach requires more lines of code but you can execute different operations depending on the exception occurred. This approach is more flexible but in some cases leads your methods to be very long due to exception handling.

Abhishek_Mishra
  • 4,341
  • 3
  • 23
  • 37