Chitika

Exception Handling

 Introduction


Exception handling is a very important yet often neglected aspect of writing robust software.
The term exception is shorthand for the phrase "exceptional event."
An exception is an error thrown by a class or method reporting an error in operation.
When an error occurs in a Java program it usually results in an exception being thrown. How you throw, catch and handle these exception matters. There are several different ways to do so. Not all are equally efficient and fail safe.
For example, dividing by zero is undefined in mathematics, and a calculation can fail if this winds up being the case because of an error in user input. In this particular case an ArithmeticException is thrown, and unless the programmer looks for this exception and manually puts in code to handle it, the program will crash stating the exception thrown and a stack trace, which would be unhelpful to a casual user of a Java program. If the programmer handles the exception, he could deliver a useful error to the user and return the user to the beginning of the program so that they could continue to use it.

The Nature of Exceptions


Broadly speaking, there are three different situations that cause exceptions to be thrown:
·         Exceptions due to programming errors: In this category, exceptions are generated due to programming errors (e.g., NullPointerException and IllegalArgumentException). The client code usually cannot do anything about programming errors.

·         Exceptions due to client code errors: Client code attempts something not allowed by the API, and thereby violates its contract. The client can take some alternative course of action, if there is useful information provided in the exception. For example: an exception is thrown while parsing an XML document that is not well-formed. The exception contains useful information about the location in the XML document that causes the problem. The client can use this information to take recovery steps.

·         Exceptions due to resource failures: Exceptions that get generated when resources fail. For example: the system runs out of memory or a network connection fails. The client's response to resource failures is context-driven. The client can retry the operation after some time or just log the resource failure and bring the application to a halt.

Types of Exceptions in Java


Java defines two kinds of exceptions:
·         Checked exceptions: Exceptions that inherit from the Exception class are checked exceptions. Client code has to handle the checked exceptions thrown by the API, either in a catch clause or by forwarding it outward with the throws clause.
·         Unchecked exceptions: RuntimeException also extends from Exception. However, all of the exceptions that inherit from RuntimeException get special treatment. There is no requirement for the client code to deal with them, and hence they are called unchecked exceptions.
By way of example, Figure 1 shows the hierarchy for NullPointerException.

The Call Stack Explained


By the call stack is meant the sequence of method calls from the current method and back to the Main method of the program.

When an error occurs within a method, the method creates an object and  hands it off to
the runtime system. The object, called an exception object, contains information
about the error, including its type and the state of the program when the error
occurred. Creating an exception object and handing it to the runtime system is
called throwing an exception.
After a method throws an exception, the runtime system attempts to find something to handle it. The set of possible "something’s" to handle the exception is the ordered list of methods that had been called to get to the method where the error occurred. The list of methods is known as the call stack (see the next figure).

The call stack.
The runtime system searches the call stack for a method that contains a block of code that can handle the exception. This block of code is called an exception handler. The search begins with the method in which the error occurred and proceeds through the call stack in the reverse order in which the methods were called. When an appropriate handler is found, the runtime system passes the exception to the handler. An exception handler is considered appropriate if the type of the exception object thrown matches the type that can be handled by the handler.
The exception handler chosen is said to catch the exception. If the runtime system exhaustively searches all the methods on the call stack without finding an appropriate exception handler, as shown in the next figure, the runtime system (and, consequently, the program) terminates.


Catching Exceptions


The java language contains keywords used specifically for testing for and handling exceptions. The ones we will be using here are try and catch, and they must be used in conjunction with one another. They sort of work like if-else:
try{
  /*
    Contains code to be tested
  */
}catch(Exception e){
  /*
    Contains code to be executed if instanced of Exception is caught
  */
}


The catch statement can look for all exceptions, using the Exception superclass, or it can catch a specific exception that you think could be thrown in the code you are testing with the try block. You can even have multiple catch blocks to catch and execute custom code for a number of different errors. A good thing to note would be that any particular exception that is caught is compared with each catch statement sequentially; so it is a good idea to put more generic exceptions, like Exception, towards the bottom of the list.

·         The try Block


The first step in constructing an exception handler is to enclose the code that might throw an exception within a try block. In general, a try block looks like the following.
try {
    code
}
catch and finally blocks . . .

·         The catch Blocks


You associate exception handlers with a try block by providing one or more catch blocks directly after the try block. No code can be between the end of the try block and the beginning of the first catch block.


try {
    
} catch (ExceptionType name) {
    
} catch (ExceptionType name) { } 

Each catch block is an exception handler and handles the type of exception indicated by its argument. The argument type, ExceptionType, declares the type of exception that the handler can handle and must be the name of a class that inherits from the Throwable class. The handler can refer to the exception with name.
The catch block contains code that is executed if and when the exception handler is invoked. The runtime system invokes the exception handler when the handler is the first one in the call stack whose ExceptionType matches the type of the exception thrown. The system considers it a match if the thrown object can legally be assigned to the exception handler's argument.
Catching the exception is done using a try-catch block. Here is an example:   


The BadNumberException parameter e inside the catch-clause points to the exception thrown from the divide method, if an exception is thrown.
If no exception is thrown by any of the methods called or statements executed inside the try-block, the catch-block is simply ignored. It will not be executed.
If an exception is thrown inside the try-block, for instance from the divide method, the program flow of the calling method, callDivide, is interrupted just like the program flow inside divide. The program flow resumes at a catch-block in the call stack that can catch the thrown exception. In the example above the "System.out.println (result);" statement will not get executed if an exception is thrown from the divide method. Instead program execution will resume inside the "catch (BadNumberException e) { }" block.
If an exception is thrown inside the catch-block and that exception is not caught, the catch-block is interrupted just like the try-block would have been.
When the catch block is finished the program continues with any statements following the catch block. In the example above the "System.out.println ("Division attempt done");" statement will always get executed.

The Throwable Superclass The catch statement also stores an instance of the exception that was caught in the variable that the programmer uses, in the previous example Exception e. While all exceptions are subclasses of Exception, Exception itself is a subclass of Throwable, which contains a nice suite of methods that you can use to get all kinds of information to report about your exceptions:
·                          getMessage()--returns the error message reported by the exception in a String
·                          printStackTrace()--prints the stack trace of the exception to standard output, useful for debugging purposes in locating where the exception occurred
·                          printStackTrace(PrintStream s)--prints the stack trace to an alternative output stream
·                          printStackTrace(PrintWriter s)--prints the stack trace to a file, this way you can log stack traces transparent to the user or log for later reference
·                          toString()--if you just decide to print out the exception it will print out this: NAME_OF_EXCEPTION: getMessage().

Using the catch you now have control over what the error message is and where it goes.
If a method needs to be able to throw an exception, it has to declare the exception(s) thrown in the method signature, and then include a throw-statement in the method. Here is an example:    public void divide(int numberToDivide, int numberToDivideBy)
    throws BadNumberException{
        if(numberToDivideBy == 0){
            throw new BadNumberException("Cannot divide by 0");
        }
        return numberToDivide / numberToDivideBy;
    }
When an exception is thrown the method stops execution right after the "throw" statement. Any statements following the "throw" statement are not executed. In the example above the "return numberToDivide / numberToDivideBy;" statement is not executed if a BadNumberException is thrown. The program resumes execution when the exception is caught somewhere by a "catch" block. Catching exceptions is explained later.
You can throw any type of exception from your code, as long as your method signature declares it. You can also make up your own exceptions. Exceptions are regular Java classes that extends java.lang.Exception, or any of the other built-in exception classes. If a method declares that it throws an exception A, then it is also legal to throw subclasses of A.

 Finally

The finally block always executes when the try block exits. This ensures that the finally block is executed even if an unexpected exception occurs. But finally is useful for more than just exception handling — it allows the programmer to avoid having cleanup code accidentally bypassed by a return, continue, or break. Putting cleanup code in a finally block is always a good practice, even when no exceptions are anticipated.
You can attach a finally-clause to a try-catch block. The code inside the finally clause will always be executed, even if an exception is thrown from within the try or catch block. If your code has a return statement inside the try or catch block, the code inside the finally-block will get executed before returning from the method. Here is how a finally clause looks:
    public void openFile(){
FileReader reader = null;
        try {
            reader = new FileReader("someFile");
            int i=0;
            while (i != -1){
                i = reader.read();
                System.out.println((char) i );
            }
        } catch (IOException e) {
            //do something clever with the exception
        } finally {
            if(reader != null){
                try {
                    reader.close();
                } catch (IOException e) {
                    //do something clever with the exception
                }
            }
            System.out.println("--- File End ---");
        }
    }
No matter whether an exception is thrown or not inside the try or catch block the code inside the finally-block is executed. The example above shows how the file reader is always closed, regardless of the program flow inside the try or catch block.


Note: If the JVM exits while the try or catch code is being executed, then the finally block may not execute. Likewise, if the thread executing the try or catch code is interrupted or killed, the finally block may not execute even though the application as a whole continues.


Important: 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.

 Advantages of Exceptions


Now that you know what exceptions are and how to use them, it's time to learn the advantages of using exceptions in your programs.

1: Separating Error-Handling Code from "Regular" Code

Exceptions provide the means to separate the details of what to do when something out of the ordinary happens from the main logic of a program. In traditional programming, error detection, reporting, and handling often lead to confusing spaghetti code.

 2: Propagating Errors Up the Call Stack

A second advantage of exceptions is the ability to propagate error reporting up the call stack of methods. Suppose that the readFile method is the fourth method in a series of nested method calls made by the main program: method1 calls method2, which calls method3, which finally calls readFile.
method1 {
    call method2;
}
method2 {
    call method3;
}
method3 {
    call readFile;
}
Suppose also that method1 is the only method interested in the errors that might occur within readFile. Traditional error-notification techniques force method2 and method3 to propagate the error codes returned by readFile up the call stack until the error codes finally reach method1—the only method that is interested in them.

3: Grouping and Differentiating Error Types

Because all exceptions thrown within a program are objects, the grouping or categorizing of exceptions is a natural outcome of the class hierarchy. An example of a group of related exception classes in the Java platform are those defined in java.ioIOException and its descendants. IOException is the most general and represents any type of error that can occur when performing I/O. Its descendants represent more specific errors.

 Best Practices for Using Exceptions

The next set of best practices show how the client code should deal with an API that throws checked exceptions.

1. Always clean up after yourself

If you are using resources like database connections or network connections, make sure you clean them up. If the API you are invoking uses only unchecked exceptions, you should still clean up resources after use, with try - finally blocks.
public void dataAccessCode(){
    Connection conn = null;
    try{
        conn = getConnection();
        ..some code that throws SQLException
    }catch(SQLException ex){
        ex.printStacktrace();
    } finally{
        DBUtil.closeConnection(conn);
    }
}
class DBUtil{
    public static void closeConnection
        (Connection conn){
        try{
            conn.close();
        } catch(SQLException ex){
            logger.error("Cannot close connection");
            throw new RuntimeException(ex);
        }
    }
}
DBUtil is a utility class that closes the Connection. The important point is the use of finally block, which executes whether or not an exception is caught. In this example, the finally closes the connection and throws a RuntimeException if there is problem with closing the connection.

2. Never use exceptions for flow control

Generating stack traces is expensive and the value of a stack trace is in debugging. In a flow-control situation, the stack trace would be ignored, since the client just wants to know how to proceed.
In the code below, a custom exception, MaximumCountReachedException, is used to control the flow.
public void useExceptionsForFlowControl() {
    try {
        while (true) {
            increaseCount();
        }
    } catch (MaximumCountReachedException ex) {
    }
    //Continue execution
}
public void increaseCount()
    throws MaximumCountReachedException {
    if (count >= 5000)
        throw new MaximumCountReachedException();
}
The useExceptionsForFlowControl() uses an infinite loop to increase the count until the exception is thrown. This not only makes the code difficult to read, but also makes it slower. Use exception handling only in exceptional situations.

3. Do not suppress or ignore exceptions

When a method from an API throws a checked exception, it is trying to tell you that you should take some counter action. If the checked exception does not make sense to you, do not hesitate to convert it into an unchecked exception and throw it again, but do not ignore it by catching it with {} and then continue as if nothing had happened.

4. Do not catch top-level exceptions

Unchecked exceptions inherit from the RuntimeException class, which in turn inherits from Exception. By catching the Exception class, you are also catching RuntimeException as in the following code:
try{
..
}catch(Exception ex){
}
The code above ignores unchecked exceptions, as well.

5. Log exceptions just once

Logging the same exception stack trace more than once can confuse the programmer examining the stack trace about the original source of exception. So just log it once.

Summary


A program can use exceptions to indicate that an error occurred. To throw an exception, use the throw statement and provide it with an exception object — a descendant of Throwable — to provide information about the specific error that occurred. A method that throws an uncaught, checked exception must include a throws clause in its declaration.
A program can catch exceptions by using a combination of the try, catch, and finally blocks.
The try block identifies a block of code in which an exception can occur.
The catch block identifies a block of code, known as an exception handler, that can handle a particular type of exception.
The finally block identifies a block of code that is guaranteed to execute, and is the right place to close files, recover resources, and otherwise clean up after the code enclosed in the try block.
The try statement should contain at least one catch block or a finally block and may have multiple catch blocks.
The class of the exception object indicates the type of exception thrown. The exception object can contain further information about the error, including an error message. With exception chaining, an exception can point to the exception that caused it, which can in turn point to the exception that caused it, and so on.


public void callDivide(){
 try {
              int result = divide(2,1);
            System.out.println(result);
        } catch (BadNumberException e) {
            //do something clever with the exception
            System.out.println(e.getMessage());
        }
        System.out.println("Division attempt done");
 }