Wednesday, 12 December 2012

Advanced - Exception Handling in java

How to create an Exception

Any checked exception can be a subclass of java.lang.Exception hierarchy or java.lang.Throwable class

Unchecked exception can be subclassed for java.lang.Error or java.lang.RuntimeException hierarchy classes

Example 
public class LowerBoundException extends java.lang.Exception
{
    int errorCode=-1;
    public LowerBoundException(final int errorCode, final String message)
    {
        super(message);
        this.errorCode=errorCode;
    }
}

Creating Exceptions - with Throws and Throw

Throws - says method is expected to throw the specified exceptions. The caller show either handle those with appropriate try catch block or re- throw them down the call stack.

Throw - throw an error condition to the caller of the method


Example
public class  Validator
{
      static int lower=50;
      public void validate(final int value) throws LowerBoundException
      {
            If(value < lower)
            {
                  throw new LowerBoundException(100,  value + " is less than "+lower);
            }
      }

}

Exception Handling - with try, catch & finally

The code inside the block will be handled for errors.
Catch - handle the respective type of exception.
Finally - regardless of whether the code inside the try throws an exception or not, the finally block will be executed. This will be used for any form up cleanup activities.

The finally block is a key tool for preventing resource leaks. When closing a file or otherwise recovering resources, place the code in a finally block to ensure that resource is always recovered.


Example
public class ValidatorTest
{
 public static void main(String args[])
 {
  Validator validator = new Validator();
  try
  {
      validator.validate(30); //throws LowerBoundException
      validator.validate(50);
      validator.validate(100);
  }catch(LowerBoundException lbe)
  {
        System.out.println("--Exception :: "+lbe.getMessage());
        lbe.printStackTrace();
  }
  finally   //cleanup
  {
        validator=null;
  }
 }
}

 

Catching More Than One Type of Exception with One Exception Handler

In Java SE 7 and later, a single catch block can handle more than one type of exception. This feature can reduce code duplication and lessen the temptation to catch an overly broad exception.

In the catch clause, specify the types of exceptions that block can handle, and separate each exception type with a vertical bar (|):

Example
catch (IOException|SQLException ex) {
    logger.log(ex);
    throw ex;
}

 

The try-with-resources Statement 

This is available in JDK 1.7. The try-with-resources statement is a try statement that declares one or more resources. A resource is an object that must be closed after the program is finished with it. The try-with-resources statement ensures that each resource is closed at the end of the statement. Any object that implements java.lang.AutoCloseable, which includes all objects which implement java.io.Closeable, can be used as a resource.

The following example reads the first line from a file. It uses an instance of BufferedReader to read data from the file. BufferedReader is a resource implementing java.lang.AutoClosable in Java SE 7. Because the BufferedReader instance is declared in a try-with-resource statement, it will be closed regardless of whether the try statement completes normally or abruptly


static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader br =  new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}

Prior to Java SE 7, the finally block was used to achieve the same . The following example uses a finally block instead of a try-with-resources statement:
static String readFirstLineFromFileWithFinallyBlock(String path)  throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(path));
    try {
        return br.readLine();
    } finally {
        if (br != null) br.close();
    }
}

Exception Chaining:

A technique of handling exceptions by re-throwing a caught exception after wrapping it inside a new exception.  This is very helpful in wrapping  unchecked exceptions into a checkedexception.   The entire trace of errors is captured in the stacktrace of the exception

Logging Exceptions:

With Exception e;
Exception Methods
What does it do?
e.toString()
Fetches the exception name with Message
e.printStackTrace()
prints the entire stack trace
e.getMessage()
fetches the message of the exception

Best Practices:

  1. Do not propogate implementation-specific exception propogate the business/user Layer. If there is a SQLException while logging in , the User does not need to know about the SQLException. All that they want to see is "Could not Login".
  2. Never swollow or ignore exceptions. Do not catch exception and return. They should be logged or nested in another exception when rethrowing.
    try
    {
      …………..
    }catch(SQLException se)
    {
    }
    
  3. Always catch the  subclass exception first and then the superclass.
  4.  Log exception Only once. Do not print stacktrace  unless it is very necessary for debugging.
  5. Print stacktrace using log.debug(). 
  6. Always cleanup after exception using finally
  7. Exception naming is very important. Use Appropriate names matching what the exception carries.
  8. Throw early and catch late. Throw exceptions as soon as you find it if it cannot be handled.

References

http://docs.oracle.com/javase/tutorial/essential/exceptions/index.htm
http://doc.sumy.ua/prog/java/langref/ch09_01.htm

1 comment: