Saturday, October 25, 2008

Exception Handling Strategy

Effective exception handling will make programs more robust and easier to debug. Exceptions are a tremendous debugging aid because they answer these three questions:
What went wrong?
Where did it go wrong?
Why did it go wrong?

Below are the three steps I have found to be effective in dealing with Exception Handling:
 
1. Be Specific
User defined Exceptions can be created by sub classing the Java Exception class. Java makes it fairly easy to be specific when catching exceptions because we can specify multiple catch blocks for a single try block, each handling a different type of exception in an appropriate manner.
In the below example each exception describes a particular scenario:  Sum Greater Than Threshold, Sum Lesser Than Threshold, Missing Arguments or Arguments Incompatible Exception. The more specific the exception, the better our program answers what went wrong. It is important to be specific when catching exceptions, as well. 
try {
  // add my numbers
} catch (SumGreaterThanThresholdException sgtt) {
// do something
} catch (SumLesserThanThresholdException sltt) {
// do something
} catch (MissingArgumentsException ma) {
// do something
} catch (ArgumentsIncompatibleException aie) {
// do something
}

2. Throw Early
The exception stack trace helps pinpoint where an exception occurred by showing us the exact sequence of method calls that lead to the exception, along with the class name, method name, source code filename, and line number for each of these method calls. Consider the stack trace below:
java.lang.NullPointerException
    at java.io.FileInputStream.open(Native Method)
    at java.io.FileInputStream.(FileInputStream.java:13)
    at example.ExcepExample.readFile(ExcepExample.java:25)
    at example.ExcepExample.main(ExcepExample.java:38)
This shows that the open() method of the FileInputStream class threw a NullPointerException. So the problem must have occurred in one of the preceding methods, which fortunately are also displayed in the stack trace. By stepping backwards through the stack trace and investigating our code, we determine that the error was caused by passing a null filename parameter to the readFile() method. 

3. Catch Late
A common mistake of many Java developers, is to catch an exception before the program can handle it in an appropriate manner. The Java compiler reinforces this behavior by insisting that checked exceptions either be caught or declared. The natural tendency is to immediately wrap the code in a try block and catch the exception to stop the compile from reporting errors.
      
try {
  // open file
} catch (FileNotFoundException e) {
Logger.error(“Exception occurred”, e);
}

The question is what to do with an exception after it is caught? The worst thing to do is nothing. An empty catch block swallows the exception, and all information about what, where, and why something went wrong is lost forever. Logging the exception is slightly better, since there is at least a record of the exception. 
Catching an exception too early, before it can properly be handled, often leads to further errors and exceptions.  Often the best approach is to simply let it go; don't catch the exception immediately. Leave that responsibility up to the caller to decide on the action.

Public File readMyFile(String fname) throws IllegalArgumentException {
       If (fname == null) {
               throws new IllegalArgumentException(“File Name not specified”);
       }
       // do something
}

Of course, eventually, program needs to catch exceptions, or has to terminate unexpectedly. The main trick is to catch exceptions at the appropriate layer, where the program can either meaningfully recover from the exception and continue without causing further errors, or provide the user with specific information, including instructions on how to recover from the exception. When it is not practical for a method to do either of these, simply let the exception go so it can be caught later on and handled at the appropriate level.

Conclusion
Experienced developers know that the hardest part of debugging usually is not fixing the bug, but finding where in the volumes of code the bug hides. By following the three rules in this article, you can help exceptions help you track down and eradicate bugs and make your programs more robust and user-friendly.




Subscribe to Exception Handling RSS by Email