Friday 13 January 2012

Effective Java Exception handling

1. Use checked exceptions when you know that or you can recover  from the exception without any side affects.
2. The best use of exceptions is to translate exception in the calling method to the exception which is more appropriate for it and you should let the cause of the exception flow from the called methods to the calling methods.
For this you should have one of the constructors of your Exception classes like
 1: // Exception with chaining-aware constructor
 2:   class HigherLevelException extends Exception {
 3:       HigherLevelException(Throwable cause) {
 4:           super(cause);
 5:       }
 6:   }
You can also use the Throwable.initCause method for this if you don’t have the constructor like the one above.
3. Don’t use the 2nd point too much if the lower level method can get away with the exception, then you should do that. Don’t overload the calling methods too much to handle the exceptions thrown by the lower methods.
4. If you are declaring your own exception class you can always include some methods or attributes which can be used to convey more about the exception when it occurs.
5. Try to reuse exceptions (comes generally when you are creating your own API). The most reusabel exceptions are
IllegalArgumentException, IllegalStateException, NullPointerException, IndexArrayOutOfBounds and some more.
6. Most importantly, use Exceptions only for Exceptional conditions. Don’t write your logic which is based on exceptions. For example, don’t do like this
 1: // wrong usage of exception handling
 2: try {
 3:     someObject.someMethod();
 4: } catch (NullPointerException npe)
 5: {
 6:     // other code
 7: }
7. If rather than Exception you can have state testing method before actually using a state-dependent method like checking iterator.hasNext() before executing the iterator.next() method is more appropriate.
8. All of the unchecked throwables you implement should subclass  RuntimeException (directly or indirectly).
9. Use runtime exceptions to indicate programming errors. The great majority of runtime exceptions indicate precondition violations. A precondition violation is simply a failure by the client of an API to adhere to the contract established by the API specification. For example, the contract for array access specifies that the array index must be between zero and the array length minus one. ArrayIndexOutOfBoundsException indicates that this precondition was violated.
10. Always declare checked exceptions individually, and document precisely the conditions under which each one is thrown using the Javadoc @throws tag. Don’t take the shortcut of declaring that a method throws some superclass of multiple exception classes that it can throw. As an extreme example, never declare that a method “throws Exception” or, worse yet, “throws Throwable.”
11.Use the Javadoc @throws tag to document each unchecked exception that a method can throw, but do not use the throws keyword to include unchecked exceptions in the method declaration.  It is important that the programmers using your API be aware of which exceptions are checked and which are unchecked, as their responsibilities differ in these two cases. The documentation    generated by the Javadoc @throws tag in the absence of the method header generated by the throws declaration provides a strong visual clue to help the programmer distinguish checked exceptions from unchecked.
12. If an exception is thrown by many methods in a class for the same reason, it is acceptable to document the exception in the class’s documentation comment rather than documenting it individually for each method. A common example is NullPointerException. It is fine for a class’s documentation comment to say, “All methods in this class throw a NullPointerException if a null object reference is passed in any parameter,” or words to that effect.
13. To capture the failure, the detail message of an exception should contain the values of all parameters and fields that “contributed to the exception. You must write the toString() method of your exception carefully.
14. Failure Atomicity(Object remains in consistence state after a failure)-
ways to achieve failure atomicity:
a. A closely related approach to achieving failure atomicity is to order the computation so that any part that may fail takes place before any part that modifies the object.
b. This approach is a natural extension of the previous one when arguments cannot be checked without performing a part of the computation.
c. A third and far less common approach to achieving failure atomicity is to write recovery code that intercepts a failure that occurs in the midst of an operation and causes the object to roll back its state to the point before the operation began. This approach is used mainly for durable (disk-based) data structures.
d.A final approach to achieving failure atomicity is to perform the operation on a temporary copy of the object and to replace the contents of the object with the temporary copy once the operation is complete. This approach occurs naturally when the computation can be performed more quickly  once the data has been stored in a temporary data structure. For example, Collections.sort dumps its
input list into an array prior to sorting to reduce the cost of accessing elements in the inner loop of the sort. This is done for performance, but as an added benefit, it ensures that the input list will be untouched if the sort fails.
As a rule, any generated exception that is part of a method’s specification should leave the object in the same state it was in prior to the method invocation. Where this rule is violated, the API documentation should clearly indicate what state the object will be left in.
15. An empty catch block defeats the purpose of exceptions, which is to force you to handle exceptional conditions. At the very
least, the catch block should contain a comment explaining why it is appropriate to ignore the exception.

No comments:

Post a Comment