Tuesday, June 10, 2014

Exception Handling in Java

Imagine you’re about to board an airplane to Geneva to attend an important conference. At the last minute, you learn that the flight has been cancelled because the pilot is not feeling well. Fortunately, the airline quickly arranges for an alternative pilot, allowing the flight to take off at its originally scheduled time. What a relief.

This example illustrates how exceptional conditions can modify the initial flow of an action and demonstrates the need to handle those conditions appropriately. 

In Java, an exceptional condition (like the illness of a pilot) can affect the normal code flow (airline flight operation). In this context, the arrangement for an alternative pilot can be compared to an exception handler.

Exceptions are objects that are thrown by an application or the Java Virtual Machine (JVM) when an error of some sort occurs. Java provides a wide range of predefined exceptions and allows the developer to declare and create their own exception classes.

Examples of exception cases: trying to access an array position not available, checked exceptions(gives compile time errors, if not handled properly), stack overflow error, etc.

  • ArrayIndexOutofBoundsException - thrown at run time.
  • Checked exception, FileNotFoundException, thrown by FileInputStream is not "caught" by code.
  • StackOverflowError at run time. A method calls itself recursively.
3 types:

  1. Program Errors - internal flaws in code
  2. Improper use of code - 
  3. Resource-related failures

When the error is not caught, the continued execution of the program can lead to unpredictably and possibly disastrous consequences.

Traditional Approach:

A traditional approach to handling exceptions is to return an error code from a procedure. For example, a function may normally return a zero(0) if it executed without an error. If an error occurs, a non-zero value(-1) would be returned. Problems with this approach:
  • Be unaware that the function returns an error code.
  • Forget to check for an error
  • Ignore the error completely
Another approach : "catch" errors

When a routine detects an error, it "throws" an exception object. The exception object is then returned to the caller which then catches and handles the error.

The try, catch, and finally blocks constitute the core of the exception handling mechanism used in Java.

The Throwable class is the superclass of all errors and exceptions in the Java language.
java.lang.Object
  extended by java.lang.Throwable
Direct Known Subclasses:
Error, Exception
Only objects that are instances of this class (Throwable class or one of its sub-classes) are thrown by the Java Virtual Machine or can be thrown by the Java throw statement. Similarly, only this class or one of its sub-classes can be the argument type in a catch clause. 
Checked Exceptions - Exceptions that need to be dealt with in the code.
Unchecked Exceptions - Exceptions that do not need to be dealt with in the code. They include exceptions, such as division by zero and array subscripting errors.

A checked exception requires the client to either catch the exception or explicitly pass it up the call hierarchy.

Uncaught exceptions are propagated to the next higher context until they are caught or they are thrown from main, where an error message and stack trace will be printed.

Traditional try-catch-finally block:

Creating try-catch-finally blocks
When you work with exception handlers, you often hear the terms try, catch, and finally. Before you start to work with these concepts, I’ll answer three simple questions:

■ Try what?
              First you try to execute your code. If it does not execute as planned, you handle the exceptional conditions using a catch block.
■ Catch what?
              You catch the exceptional event arising from the code enclosed within the try
block and handle the event by defining appropriate exception handlers.
■ What does finally do?
              Finally, you execute a set of code, in all conditions, regardless of whether the
code in the try block throws any exceptions. 


A try block is used to surround code that might throw exceptions.

The catch blocks are added after a try block to "catch" exceptions. The statements in the catch block provide blocks of code to "handle" the error. Only one catch block is ever executed when an exception is thrown.

A finally clause can optionally be used after the catch blocks. It is guaranteed to execute even if code within a try or a catch block throws or does not throw an exception. The finally clause is guaranteed to run and generally contains "clean-up" code.

A finally block will not execute if the System.exit method is invoked in a try or catch block.

Using Exceptions, you get two benefits:
a) Your normal flow of execution is separated from exception handling code, as the exception handling is done within catch blocks.
b) Exceptions also help in providing stack trace so that actual cause of exception can be easily traced.

For a try block, you can define multiple catch blocks, but only a single finally block.

Multiple catch blocks are used to handle different types of exceptions.

finally block is used to define cleanup code—code that closes and releases resources, such as file handlers and database or network connections.

Example:


public class MainClass {
  public static void main(String args[]) {
    int urAns, urDiv;
    try {
      urDiv = 0;
      urAns = 25 / urDiv;
      System.out.println("Division is successful");
    } 
    catch (ArithmeticException e) {
      System.out.println("Division by zero not Possible!");
    }
finally {
System.out.println("Finally block executed");
}
    System.out.println("This will print out after Exception Handling");

  }
}

o/p:
Division by zero not Possible!
Finally block executed
This will print out after Exception Handling

Will a finally block execute even if the try/catch block defines a return statement?

A finally block will execute even if the code in the try block or any of the catch blocks defines a return statement.

There are a few scenarios in Java in which a finally block does not execute:
■ Application termination—The try or the catch block executes System.exit, which terminates the application
■ Fatal errors—A crash of the JVM or the OS

What happens if both a catch and a finally block define return statements?

If both catch and finally blocks define return statements, the calling method will receive a value from the finally block. This is only when catch and finally block just returns literals.

What happens if a finally block modifies the value returned from a catch block?

If a catch block returns a primitive data type, the finally block can’t modify the value being returned by it. Control in the catch block copies the value of returnVal to be returned before it executes the finally block, so the returned value is not modified when finally executes. It is pass-by-value.

public class TestExceptionsExample {
    
    int getInt() {
    int returnVal = 10;
        try {
            String[] students = {"Harry", "Paul"};
            System.out.println("Initial Value: " + returnVal);
            System.out.println(students[5]);
        }
        catch (Exception e) {
            System.out.println("About to return in Catch block :" + returnVal);
            return returnVal;
        }
        finally {
            returnVal += 10;
            System.out.println("Return value in finally block:" + returnVal);
        }
        return returnVal;
    }
    public static void main(String args[]) {
        TestExceptionsExample var = new TestExceptionsExample();
        System.out.println("In Main: " + var.getInt());
    }

}

o/p:
Initial Value: 10
About to return in Catch block :10
Return value in finally block:20

In Main: 10

When the finally block executes, it can access the value of the object referred in the catch block and can modify it. The modified value is returned to the method main.
Remember that primitives are passed by value and objects are passed by reference.

public class TestExceptionsExample {
    
    StringBuilder getStringBuilder() {
        StringBuilder returnVal = new StringBuilder("Raghu");
        try {
            String[] students = {"Harry", "Paul"};
            System.out.println("Initial Value: " + returnVal);
            System.out.println(students[5]);
        }
        catch (Exception e) {
            System.out.println("About to return in Catch block : " + returnVal);
            return returnVal;
        }
        finally {
            returnVal.append("nath");
            System.out.println("Return value in finally block : " + returnVal);
        }
        return returnVal;
    }
    public static void main(String args[]) {
        
        TestExceptionsExample var = new TestExceptionsExample();
        System.out.println("In Main : " + var.getStringBuilder());
    }
}

o/p:
Initial Value: Raghu
About to return in Catch block : Raghu
Return value in finally block : Raghunath

In Main : Raghunath

Watch out for code that returns a value from the catch block and modifies it in the finally block. If a catch block returns a primitive data type, the finally block can’t modify the value being returned by it. If a catch block returns an object, the finally block can modify the value being returned by it.

Notes to remember:

■ A try block may be followed by multiple catch blocks, and the catch blocks may be followed by a single finally block.
■ A try block may be followed by either a catch or a finally block or both. But a finally block alone would not suffice if code in the try block throws a checked exception. In this case, you need to catch the checked exception or declare it to be thrown by your method. Otherwise your code won’t compile.
■ The try, catch, and finally blocks can’t exist independently.
■ The finally block can’t appear before a catch block.
■ A finally block always executes, regardless of whether the code throws an exception.

Can I rethrow an exception or the error I catch?

You can do whatever you want with an exception. Rethrow it, pass it on to a method, assign it to another variable, so on.

When you rethrow a checked exception, it’s treated like a regular thrown checked exception, meaning that all the rules of handling a checked exception apply to it.

You can rethrow a runtime exception, but you’re not required to catch it, nor must you modify your method signature to include the throws clause. The simple reason for this rule is that RuntimeExceptions aren’t checked exceptions, and they may not be caught or declared to be thrown by your code.

If a method does not wish to handle the checked exceptions thrown by a method it calls, it can throw these exceptions using the throws clause in its own method signature.

I can create nested loops, so can I create nested try-catch blocks too?

The simple answer is yes, you can define a try-catch-finally block within another try-catch-finally block. Theoretically, the levels of nesting for the try-catch-finally blocks have no limits.


Categories of exceptions:

■ Exceptions are divided into three categories: checked exceptions, runtime (or unchecked exceptions), and errors. These three categories share IS-A relationships
(inheritance).

■ Subclasses of the class java.lang.RuntimeException are categorized as runtime
exceptions.
■ Subclasses of the class java.lang.Error are categorized as errors.
■ Subclasses of the class java.lang.Exception are categorized as checked exceptions if they are not subclasses of class java.lang.RuntimeException.
■ The class java.lang.RuntimeException is a subclass of the class java.lang.Exception.
■ The class java.lang.Exception is a subclass of the class java.lang.Throwable.
■ The class java.lang.Error is also a subclass of the class java.lang.Throwable.
■ The class java.lang.Throwable inherits the class java.lang.Object.

Checked exceptions:

■ A checked exception is an unacceptable condition foreseen by the author of a method, but outside the immediate control of the code.
■ FileNotFoundException is a checked exception. This exception is thrown if the file that the code is trying to access can’t be found.
■ All checked exceptions are a subclass of the java.lang.Exception class, not a subclass of java.lang.RuntimeException. It’s interesting to note, however, that the class java.lang.RuntimeException itself is a subclass of the class java.lang.Exception.
■ If a method calls another method that may throw a checked exception, either it
must be enclosed within a try-catch block or the method should declare this
exception to be thrown in its method signature.

Runtime exceptions:

■ Runtime exceptions represent programming errors. These occur from inappropriate use of another piece of code. For example, NullPointerException is a runtime exception that occurs when a piece of code tries to execute some code on a variable that hasn’t been assigned an object and points to null. Another example is ArrayIndexOutOfBoundsException, which is thrown when a piece of code tries to access an array of list elements at a nonexistent position.
■ A runtime exception is a subclass of java.lang.RuntimeException.
■ A runtime exception isn’t a part of the method signature, even if a method may
throw it.
■ A runtime exception may not necessarily be caught by a try-catch block.

Errors:
■ An error is a serious exception, thrown by the JVM as a result of an error in the
environment state, which processes your code. For example, NoClassDefFound-
Error is an error thrown by the JVM when it is unable to locate the .class file it is
supposed to run.
■ StackOverflowError is another error, thrown by the JVM when the size of the
memory required by the stack of the Java program is greater than what the JRE
has offered for the Java application. This error usually occurs as a result of infinite
or highly nested loops.
■ An error is a subclass of the class java.lang.Error.
■ An error need not be a part of a method signature.
■ Though you can handle the errors syntactically, there is little that you can do
when these errors occur. For example, when the JVM throws OutOfMemory-
Error, your code execution will halt, even if you define an exception handler
for it.

Commonly occurring exceptions, categories, and classes:

■ ArrayIndexOutOfBoundsException is a runtime exception that’s thrown when a piece of code tries to access an array position out of its bounds—when an array is accessed either at a position less than 0 or at a position greater than or equal to its length.

■ IndexOutOfBoundsException is a runtime exception that’s thrown when a piece of code tries to access a list position that’s out of its bounds—when the position is either less than 0 or greater than or equal to the list’s size.

■ The class ArrayIndexOutOfBoundsException extends the class java.lang.IndexOutOfBoundsException, which extends the class java.lang.RuntimeException.

■ In typical programming conditions, the ArrayIndexOutOfBoundsException
shouldn’t be thrown programmatically.

■ One of the main reasons for the JVM taking the responsibility for throwing this exception itself is that this exception isn’t known until runtime and depends on the array or list position that’s being accessed by a piece of code. Most often, a variable is used to specify this array or list position, and its value may not be known until runtime.

■ ClassCastException is a runtime exception. java.lang.ClassCastException
extends java.lang.RuntimeException.
■ ClassCastException is thrown when an object fails an IS-A test with the class
type it is being cast to.
■ You can use the operator instanceof to verify whether an object can be cast to
another class before casting it.

■ IllegalArgumentException is a runtime exception. java.lang.Illegal-
ArgumentException extends java.lang.RuntimeException.
■ IllegalArgumentException is thrown to specify that a method has been passed
illegal or inappropriate arguments.
■ Even though IllegalArgumentException is a runtime exception, programmers
usually use this exception to validate the arguments that are passed to a
method, and the exception constructor is passed a descriptive message specifying
the exception details.

■ IllegalStateException is a runtime exception. java.lang.IllegalState-
Exception extends java.lang.RuntimeException.
■ IllegalStateException may be thrown programmatically.
■ As a programmer, you can throw IllegalStateException to signal to the calling
method that the method that’s being requested for execution isn’t ready to
start its execution or is in a state in which it can’t execute.
■ For example, you can throw IllegalStateException from your code if an
application tries to modify an SMS that has already been sent.

■ NullPointerException is a runtime exception. The class java.lang.Null-
PointerException extends java.lang.RuntimeException.
■ NullPointerException is thrown by the JVM if you try to access a method or
variable of an uninitialized reference variable.

■ NumberFormatException is a runtime exception. java.lang.NumberFormat-
Exception extends java.lang.IllegalArgumentException. java.lang.Illegal-
ArgumentException extends java.lang.RuntimeException.
■ You can throw NumberFormatException from your own method to indicate that
there’s an issue with the conversion of a String value to a specified numeric
format (decimal, octal, hexadecimal, or binary).

■ Runtime exceptions arising from any of the following may throw ExceptionIn-
InitializerError:
– Execution of an anonymous static block
– Initialization of a static variable
– Execution of a static method (called from either of the previous two items)
■ The error ExceptionInInitializerError can be thrown only by an object of a
runtime exception.
■ ExceptionInInitializerError can’t be thrown if a static initializer block
throws an object of a checked exception, because the Java compiler is intelligent
enough to determine this condition and it doesn’t allow you to throw an
unhandled checked exception from a static initialization block.

■ StackOverflowError is an error. java.lang.StackOverflowError extends
java.lang.VirtualMachineError.
■ Because StackOverflowError extends VirtualMachineError, it should be left
to be managed by the JVM.
■ The StackOverflowError error is thrown by the JVM when a Java program calls
itself so many times that the memory stack allocated to execute the Java program
“overflows.”

■ NoClassDefFoundError is an Error. java.lang.NoClassDefFoundError extends
java.lang.LinkageError. java.lang.LinkageError extends java.lang.Error.
■ NoClassDefFoundError is thrown by the JVM or a ClassLoader when it is
unable to load the definition of a class required to create an object of the class.
■ Don’t confuse the exception thrown by Class.forName(), used to load the
class, and NoClassDefFoundError thrown by the JVM. Class.forName() throws
ClassNotFoundException.

■ OutOfMemoryError is thrown by the JVM when it’s unable to create objects on the
heap and the garbage collector may not be able to free more memory for the JVM.














No comments:

Post a Comment