Exception Handling – Part II

Java has a hierarchy defined for exception classes. This tutorial is second in the multi-part series for java exception handling. Previous tutorial serves as an introduction to java exception handling and this one takes it to the next level.

Exception Hierarchy

Throwable is the base class of all exceptions in java. Throwable has two direct sub classes namely Exception and Error. These two classes creates clean separation of exception types. Exception and all its sub classes are that can be handled within the program. Error and all its sub classes are expected to be handled by the program. Error and its sub type are used by Java’s run time system to indicate problems related to run time environment like out of memory or stack overflow. For example, out of memory problem(OutOfMemoryError) cannot be fixed using program code and is not expected to be handled by the program.
In the below image java’s own exception classes and it hierarchy is shown. Only important Errors and Exceptions are shown. With every release of java there are numerous new exceptions added to the package and we have a lot of them now. Green colored classes are exceptions that can be handled in a program. Red colored classes are that cannot be handled. Packaging wise, every Java package has its set of exceptions organized within itself. For example, java.io.* contains all IO related exceptions in java.io.* itself, so thats where we gotta search for exception classes to have a look at it.
ExceptionHierarchyBase
RuntimeException is a sub class of Exception class. RuntimeException and all it sub classes are need not be declared in throws clause of a method. These are understood to be regular exceptions that can occur in any context and java says that we need not declare them in thows of a method. All exceptions other than RuntimeException and its subclasses must be declared in throws clause of a method. To highlight that, in the image RuntimeException and its subclassess are shown in dark green. RuntimeException and all its sub classes are called un-checked exceptions, since they need not be declared using throws in method signature and all other java exceptions are checked exceptions.
ExceptionHierarchy

Exception StackTrace

When a java exception is thrown we get a nice stack trace to help for debugging purposes and to know more information about the exception and its source.
public class ExceptionStack {
    public static void main(String args[]) {
      int[] tempArr = new int[5];
    System.out.println(tempArr[10]);
    }
}
If the above source code listing is executed we get the following exception.
Exception in thread “main” java.lang.ArrayIndexOutOfBoundsException: 10
at ExceptionStack.main(ExceptionStack.java:4)

This is the exception stack trace which gives information on what type of exception is thrown and which line number, method is the cause of it. For this example, the stack trace tells that the type of exception occurred is ArrayIndexOutOfBoundsException, it occurred because it 10 is not a valid array location, then the exception occurred at source code line number 4, in method main. This is sufficient to understand and fix this issue.
Exception stack trace also give complete list of method calls in the sequence flow till it reached the exception line. Look at the following source code listing where the line where exception can happen is moved into a method.
public class ExceptionStack {
    public static void main(String args[]) {
    int value = get(10);
    System.out.println(value);
    }
 
    public static int get(int location) {
    int[] tempArr = new int[5];
    int result = 0;
    result = tempArr[location];
    return result;
    }
}
For this example source code, we get the following exception stack trace.
Exception in thread “main” java.lang.ArrayIndexOutOfBoundsException: 10
at ExceptionStack.methodA(ExceptionStack.java:8)
at ExceptionStack.main(ExceptionStack.java:3)
This stack trace adds one more line of information. Starting from bottom-up, it gives the first method where the execution flow started and the call is made, then the next method in sequence flow. Similarly if we have multiple methods, we will get all the methods in the sequence flow listing in the stack trace.

Handle an Exception

Let us continue with the above example and see how we can handle an exception. We should enclose the block of lines where the exception can occur in a try block and followed by that we should have a catch block. In catch(…) we should specify the type of exception which we intend to handle. The exception class that is specified in catch block will handle exceptions including all its sub types. That is, if we specify RuntimeException in catch, it will catch IndexOutOfBoundsException and also ArrayIndexOutOfBoundsException too. That is, it will catch RuntimeException and all its sub types. Refer the above image for relationship hierarchy. So, if we put Exception is catch block it will handle all possible java exceptions. Only one catch block is sufficient forever. This is technically correct but it is not a best practice. We should catch the lowest possible exception in the hierarchy. Instead putting RuntimeException, we should have ArrayIndexOutOfBoundsException in catch block.
public class ExceptionStack {
    public static void main(String args[]) {
  int value = get(10);
  System.out.println(value);
    }
 
    public static int get(int location) {
  int[] tempArr = new int[5];
  int result = 0;
  try {
    result = tempArr[location];
  } catch(ArrayIndexOutOfBoundsException exception) {
    exception.printStackTrace();
  }
  return result;
    }
}
What have we done in the above example source code? We have just enclosed the code block where an exception can occur using try and a catch block. In catch block we say that, we intend to handle ArrayIndexOutOfBoundsException and we print the trace. I have purposefully added the exception.printStackTrace(); line in the catch block. If we run this code listing the output we get is exactly the same as the one we got in the previous example. We have handled the exception but have done nothing. One more best practice is, just logging an exception and doing nothing is not good (unless otherwise we don’t have anything else to do, just the program execution needs to continue case).
public class ExceptionStack {
    public static void main(String args[]) {
  int value = get(10);
  System.out.println(value);
    }
 
    public static int get(int location) {
  int[] tempArr = new int[5];
  int result = 0;
  try {
    result = tempArr[location];
  } catch(ArrayIndexOutOfBoundsException exception) {
        System.out.println("No such element and so setting zero");
    result = 0;
  }
  return result;
    }
}
In the above example, we have handled the exception in an appropriate way. We have logged the message then returned 0 and continuing with program flow. This is just an example, the business may not warrant to return 0 and in that case we cannot use this. This is just an example to show meaningful handling of an exception. If it is all about logging and proceeding with the flow, even an if-block can do the job and no exception handling is required. So, use exception handling judiciously. There should be a meaningful purpose to it when used.

Exception Handling Control Flow

When an exception is thrown, the control just jumps out of that line and goes to the catch block of the type of exception thrown. It is not like a method call where the calling position / stack is noted and the control will return back once the called method is executed. This is just like a go to (jump) and the control will never come back to the line where exception occurred. Lines of code that is between the line where exception occurred and the try block ends will never be executed.
There can be multiple catch blocks after try. If exception of same parent class needs to be handled (caught), then they should be ordered by most subclass first and then followed by super classes. For example, ArrayIndexOutOfBoundsException first, then we will have RuntimeException and thereafter Exception in this given order. finally block will always be executed irrespective of an exception thrown or not and this will be the last block of code executed.
exceptionControlFlow
Yes, this exception handling tutorial series is not complete yet and continue reading the part III of exception handling series try-with-resources.

0 comments:

Post a Comment