Exception Handling
An exception is an abnormal condition
that arises in a code sequence at run time. In other words, an exception is a run-time
error. An exception can occur for many different
reasons, like a user entering invalid data or a file that needs
to be opened is not found or a network connection has been lost in the middle
of communications, or the JVM has run out of memory.
A Java exception is an object describing an
exceptional condition that has occurred in a piece of code. When an exceptional
condition arises, an object representing that exception is created and thrown in the method that caused the error. That method may choose to handle
the exception itself, or pass it on. Either way, at some point, the exception
is caught and processed. Exceptions can be generated by the Java run-time system,
or they can be manually generated by your code.
Java exception handling is managed via five
keywords: try, catch, throw, throws, and finally. Briefly, here is
how they work. Program statements that you want to monitor for exceptions are
contained within a try block. If an exception
occurs within the try block, it is thrown. Your
code can catch this exception (using catch) and handle it in some rational manner. System-generated
exceptions are automatically thrown by the Java run-time system. To manually
throw an exception, use the keyword throw. Any exception that is thrown out of a method
must be specified as such by a throws clause. Any code that
absolutely must be executed after a try block completes is put in a
finally block.
This is the general form of an
exception-handling block:
try {
// block of code to monitor for errors
}catch (ExceptionType1 ex1) {
// exception handler for ExceptionType1
}catch (ExceptionType2 ex2) {
// exception handler for ExceptionType2
}
// ...
finally {
// block of code to be executed after try block
ends
}
Here, ExceptionType
is the type of exception that has occurred.
Exception Types
There are three categories of exceptions:
·
Checked exceptions: A checked exception is an exception that is typically a user error
or a problem that cannot be foreseen by the programmer. For example, if a file
is to be opened, but the file cannot be found, an exception occurs. These
exceptions cannot simply be ignored at the time of compilation.
·
Runtime exceptions: A runtime exception is an exception that occurs that probably
could have been avoided by the programmer. As opposed to checked exceptions,
runtime exceptions are ignored at the time of compilation.
·
Errors: These are not exceptions at all, but problems that arise beyond
the control of the user or the programmer. Errors are typically ignored in your
code because you can rarely do anything about an error. For example, if a stack
overflow occurs, an error will arise. They are also ignored at the time of
compilation.
Common situations where Exceptions occur
Arithmetic Exception
If we divide a number by zero
E.g. int a = 50/0
Null pointer Exception
Performing any operation on a variable that has
null value
E.g. String s = null;
System.out.println(s.length);
Number Format Exception
Wrong formatting of numbers
E.g. String s = “abc”;
int I =
Integer.parseInt(s);
Array Index Out Of Bounds Exception
While inserting a value in wrong Index
E.g. int[] a = new int[5];
a[7] = 3;
Exception hierarchy
All exception types are subclasses of the
built-in class Throwable. Thus, Throwable is at the top of the exception class hierarchy. Immediately below Throwable are two subclasses that partition exceptions into two distinct branches.
One branch is headed by Exception. This class is used for exceptional conditions that user programs
should catch. This is also the class that you will subclass to create your own
custom exception types. There is an important subclass of Exception, called RuntimeException. Exceptions of this type are automatically defined for the programs that
you write and include things such as division by zero and invalid array indexing.
The other branch is topped by Error, which defines exceptions that are not expected to be caught under
normal circumstances by your program. Exceptions of type Error are used by the Java run-time system to indicate errors having to do
with the run-time environment, itself. Stack overflow is an example of such an
error.
The diagram below summarises the hierarchy of built-in java Exception classes:
Example:
File Name : ExcepTest.java
import java.io.*;
public class ExcepTest{
public static void main(String args[]){
try{
int a[] = new int[2];
System.out.println("Access element three
:" + a[3]);
}catch(ArrayIndexOutOfBoundsException
e){
System.out.println("Exception thrown :" + e);
}
System.out.println("Out
of the block");
}
}
Output
Exception thrown
:java.lang.ArrayIndexOutOfBoundsException: 3
Out of the block
Uncaught Exceptions
Suppose we remove the try…catch statements in
the above program. When the Java
run-time system detects that the index used is out of the boundary of the
array, it constructs a new exception object and then throws this
exception. This causes the execution of main()
to stop, because once an exception has been thrown, it must be caught by
an exception handler and dealt with immediately. Here, we haven’t supplied any
exception handlers of our own, so the exception is caught by the default
handler provided by the Java run-time system. Any exception that is not caught
by your program will ultimately be processed by the default handler. The
default handler displays a string describing the exception, prints a stack
trace from the point at which the exception occurred, and terminates the
program. Here is the exception generated is:
java.lang.ArrayIndexOutOfBoundException:
/ by zero
at ExcepTest.main(ExcepTest.java:5)
Notice how the class name, ExcepTest; the method name, main; the filename, ExcepTest.java and the line number, 5, are all included in the simple stack trace.
Multiple catch Clauses
In some cases, more than one exception could be
raised by a single piece of code. To handle this type of situation, you can
specify two or more catch clauses, each catching a
different type of exception. When an exception is thrown, each catch statement is inspected in order, and the first one whose type matches
that of the exception is executed. After one catch statement executes, the others are bypassed, and execution continues
after the try/catch block.
Example:
class ExceptionTest{
public static void main(String[] ar){
int[] a= new int[5];
a[0] = 10;
int l = ar.length;
try{
a[0] = a[0] / l;
a[3] = l * 2;
}catch(ArithmeticException ae){
a = 0;
}catch(ArrayIndexOutOfBoundsException
aie){
aie.printStackTrace();
}
System.out.println("a =
"+a);
}
}
This program will cause a division-by-zero
exception if it is started with no commandline arguments, since l will equal zero. It will survive the division if you provide a
command-line argument, setting l to something larger than
zero. But it will cause an ArrayIndexOutOfBoundsException, since the int array a has a length of 2, yet the program attempts to assign a value to a[3].
When you use multiple catch statements, it is important to remember that exception subclasses
must come before any of their superclasses. This is because a catch statement that uses a superclass will catch exceptions of that type
plus any of its subclasses. Thus, a subclass would never be reached if it came
after its superclass. Further, in Java, unreachable code is an error.
So we cannot use a statement catch(ArithmeticException ae) after catch(Exception e) as Exception is the super class of ArithmeticException.
Throws and Throw
If a method is capable of causing an exception
that it does not handle, it must specify this behavior so that callers of the
method can guard themselves against that exception. You do this by including a throws clause in the method’s declaration. A throws clause lists the types of exceptions that a method might throw.
type
method-name(parameter-list) throws exception-list{
// body of method
}
Example:
class ExceptionTest{
public static void main(String[] ar){
int[] a= new int[5];
a[0] = 10;
int l = ar.length;
try{
a[0] =
divide(a[0],l);
a[3] = l * 2;
}catch(ArithmeticException
ae){
a[0] = 0;
}
catch(ArrayIndexOutOfBoundsException
aie){
aie.printStackTrace();
}
System.out.println("Quotient
= "+a[0]);
}
static int divide(int x, int y) throws ArithmeticException{
return x/y;
}
}
In this example, the method devide() has the
probability of a divide by zero, but it is not handling this exception. So we
specify this by the statement throws
ArithmeticException while defining
the method. The method that calls divide(), here its main(), should make
arrangements for the exception to be caught, either by writing try…catch blocks
or by declaring them using throws
keyword.
public static void
main(String[] ar) throws ArithmeticException, ArrayIndexOutOfBoundsException{
int[] a= new int[5];
a[0] = 10;
int l = ar.length;
a[0] = divide(a[0],l);
a[3] = l * 2;
}
As there is no other method calling the main(),
the exceptions will be handled by JVM
It is also possible for your program to throw an
exception explicitly, using the throw statement. The general form
of throw is shown here:
throw ThrowableInstance;
Here, ThrowableInstance must be an object of type Throwable or a subclass of Throwable. There are two ways you can obtain a Throwable object: using a parameter in a catch clause, or creating one with the new operator. Once a throw statement is encountered, the same sequence of
steps is followed as if an exception has occurred.
Suppose the divide() method in the above example
is redefined as
static int divide(int
x, int y) throws ArithmeticException{
try{
r = x/y;
}catch(ArithmeticException e){
System.out.println(“Exception
caught inside divide()”);
throw e;
}
return r;
}
Here the exception is caught inside the catch
block in the method divide(), but the method instead of handling it throws it
again. Now this reaches main has to be handled there. So we rewrite main as:
public static void
main(String[] ar) throws ArrayIndexOutOfBoundsException{
int[] a= new int[5];
a[0] = 10;
int l = ar.length;
try{
a[0] = divide(a[0],l);
}catch(ArithmeticException a){
a[0] = 0;
System.out.println(“Exception
caught inside main()”);
}
a[3] = l * 2;
}
Output
Exception caught inside divide()
Exception caught inside main()
finally
finally creates a block of code that will be executed after a try/catch block has completed and before the code following the try/catch block. The finally block will execute whether
or not an exception is thrown. If an exception is thrown, the finally block will execute even if no catch statement matches the
exception. Any time a method is about to return to the caller from inside a try/catch block, via an uncaught exception or an explicit return statement, the finally clause is also executed just before the method returns. This can be
useful for closing file handles and freeing up any other resources that might
have been allocated at the beginning of a method (E.g. A file that is opened
needs to be closed). The finally clause is optional.
However, each try statement requires at least one catch or a finally clause.
E.g. Lets add a finally block that will print
the result of division to the above example:
class ExceptionTest{
public static void main(String[] ar){
int[] a= new int[5];
a[0] = 10;
int l = ar.length;
try{
a[0] =
divide(a[0],l);
a[3] = l * 2;
}catch(ArithmeticException
ae){
a[0] = 0;
}
catch(ArrayIndexOutOfBoundsException
aie){
aie.printStackTrace();
}finally{
System.out.println("Quotient
= "+a[0]);
}
}
static int divide(int x, int y) throws
ArithmeticException{
return x/y;
}
}
Here the value of a[0] is displayed whether or
not an exception occurs.
Note the following:
·
A catch clause cannot exist without a try
statement.
·
It is not compulsory to have finally clauses
whenever a try/catch block is present.
·
The try block cannot be present without either
catch clause or finally clause.
·
Any code cannot be present in between the try,
catch, finally blocks.
Creating Our Own Exception Subclasses
To create customized Exceptions of our own, we just
need to define a subclass of Exception. Our subclass don’t need to actually implement anything. The Exception class does not define any methods of its own. It does, of course,
inherit those methods provided by Throwable. Thus, all exceptions, including those that we
create, have the methods defined by Throwable available to them. We can
also wish to override one or more of these methods in exception classes that we
create.
Following is the list of important methods
available in the Throwable class.
SN
|
Methods with Description
|
1
|
public String getMessage()
Returns a detailed message about the exception that has occurred. This message is initialized in the Throwable constructor. |
2
|
public Throwable getCause()
Returns the cause of the exception as represented by a Throwable object. |
3
|
public String toString()
Returns the name of the class concatenated with the result of getMessage() |
4
|
public void printStackTrace()
Prints the result of toString() along with the stack trace to System.err, the error output stream. |
5
|
public StackTraceElement[] getStackTrace()
Returns an array containing each element on the stack trace. The element at index 0 represents the top of the call stack, and the last element in the array represents the method at the bottom of the call stack. |
6
|
public Throwable fillInStackTrace()
Fills the stack trace of this Throwable object with the current stack trace, adding to any previous information in the stack trace. |
Exception defines four constructors. Two were added by JDK 1.4 to support chained
exceptions, the other two are:
Exception( )
Exception(String msg)
The following example declares a new subclass of
Exception and then uses that subclass to signal an error condition in a method:
class MyException
extends Exception {
public String toString() {
return
"This is My Exception";
}
}
class ExceptionDemo {
static void calculate(int a) throws
MyException {
System.out.println("Inside calculate");
if(a > 10)
throw new
MyException(a);
System.out.println("No Exception");
}
public static void main(String
args[]) {
try
{
calculate(1);
calculate(20);
}
catch (MyException e) {
System.out.println("Caught " + e);
}
}
}
This example defines a subclass of Exception called MyException. This subclass is quite simple: it has only an
overloaded toString(
) method that displays the message of the exception. The ExceptionDemo class defines a method named calculate( ) that throws a MyException object. The exception is thrown when calculate( )’s integer parameter is
greater than 10. The main( ) method sets up an exception
handler for MyException, then calls calculate( ) with a legal value (less
than 10) and an illegal one.
Output
Inside calculate
No Exception
Inside calculate
Caught This is My Exception
No comments:
Post a Comment