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.
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.
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.
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.
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.
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).
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.
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.
Yes, this exception handling tutorial series is not complete yet and continue reading the part III of exception handling series try-with-resources.
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.
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.
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 ]); } } |
Exception in thread “main” java.lang.ArrayIndexOutOfBoundsException: 10
at ExceptionStack.main(ExceptionStack.java:4)
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; } } |
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; } } |
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; } } |
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.
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