In the previous chapter, we have seen that an InputMismatchException can be caught by a catch block defined to handle an exception of type ‘Exception’ since InputMismatchException is a subclass of Exception. It is important to know the hierarchy of exception classes to write correct programs.

Class Exception lies at the root of the exception hierarchy. Every exception type in Java is a subclass of Exception. Therefore, a catch clause designed to handle Exception can process all pre-defined exceptions of Java. However, besides the subclasses of Exception, we have subclasses of Error which represents a condition that cannot be handled by the programmer.

The exceptions that inherit from Error denote serious errors like VirtualMachineError from which a program cannot normally recover. Though it is syntaxialy correct to catch Errors also, one however should refrain from doing so. Both Exception and Error are subclasses of Throwable. (We have both Throwable class and Throwable interface).

Several other Exceptions have been extended from class Exception. We can group them into two categories. We can put the Runtime Exception into one category and all other exceptions in the other category. We will see shortly why we have grouped them in this way. The following diagram shows this hierarchy.

exception hierarchy in java

Java distinguishes between checked and unchecked exceptions. Checked exceptions are those Exceptions for which we need to provide exception handling while unchecked exceptions are those for which providing exception handlers are optional. You may know the types of exceptions that would be thrown by looking at the documentation for the method that you are calling. For example, when we are calling the nextInt() method to take an integer input from the keyboard, we should also be having an idea of the exceptions that it might throw. Look at the documentation for this method.

You will see that three types of Exceptions may be thrown by this method. Even when we have not provided exception handlers for these three methods, the compiler has not raised any objection. This is because these three Exceptions are unchecked exceptions. All exceptions of type RunTimeExcepotion or its subclasses are considered to be unchecked Exceptions. And, all exceptions of type Exception other than RunTimeExcepotion have checked exceptions. Checked exceptions should either be caught or be declared to be thrown. We shall see shortly how we may throw exceptions instead of catching them.

Here are a few Exceptions that you should be familiar with:

ArrayIndexOutOfBoundsException ( unchecked): Thrown when we try to access an array element using an invalid index, such as a negative index or an index greater to or equal to the length of the array StringIndexOutOfBoundsException (unchecked): Similar to the above but deals with Strings enacted of arrays IndexOutOfBoundsException (unchecked): A superclass of the above two Exception types NullPointerException (unchecked): Thrown when we try to dereference a null pointer i.e. when we try to access an object through a variable when the variable holds a value of null and does not hold a reference to an object

We need to keep the hierarchy of exceptions in mind when writing exception handlers for our program. For example, let us provide two catch blocks for the program we have written earlier, which takes an integral and displays it. One of these catch statements will be catching the InputMismatchException and the other would be defined to catch a general Exception. Now, what would happen if we defined the catch block for Exception first followed by a catch block for InputMismatchException?

catch (Exception e ) {
    // code
}
catch (  InputMismatchException e ) {
    // code
}

Now, compile this program. You will receive an unreachable code error saying that the second catch handler can never be reached by the program. Why does this happen? Assume that this program compiles well and we can execute it. If we enter a valid number, no catch statement would be executed. If we enter an invalid input like a String, an InputMismatchException would be thrown.

As already said, the type of Exception thrown will be compared with the types specified in the catch clauses in sequential order. So, the type InputMismatchException would be compared with the type Exception. Since InputMismatchException is a subclass of Exception, a match has occurred. The first catch block will be executed. Once a catch block is executed, the remaining blocks would be skipped and control would pass onto the final block if it exists. So, in conclusion, the second catch block would never be executed. This is why an unreachable code compilation error was generated. Therefore, we needed to catch subclass exceptions before catching superclass exceptions. The proper way to define the above code is to catch InputMismatchException first followed by Exception as shown below.

catch (  InputMismatchException e ) {
    // code
}
catch (Exception e ) {
    // code
}