An unusual situation may occur sometimes while running the programs. There might be errors and some of them may be fatal. Take a simple case of divide by zero. Older languages give some error message and halt the execution of the program. If the errors are fatal, one cannot do anything about it but if they are non-fatal, the language should allow us to do some damage control exercise. Java provides elegant way of exception handling precisely for this purpose.
One of the most important reasons for handling exception is that when a program terminates abruptly many undesirable things happen. Certain resources, like open files and the World Wide Web (WWW) connection, remain blocked. The operating system (OS) does not get them back. If your program has done any important work or calculations, the efforts are lost. When exception occurs, the program stops running. We cannot do anything about it afterwards. But if we handle exceptions properly, we can do some damage control exercise. We can give the allocated resources back to the OS and save some results. In lighter vain, we can send SOS to our friends.
Let us start our study with a simple example.
Problem: Write a program to show divide by zero exception.
Solution: See Program 19.1.
PROGRAM 19.1 Divide by zero exception
// ex2.java
class ex2
{ public static void main (String args [])
{ int num = 20;
int den = 0 ;
int result;
result = num / den ;
System.out.println(“--->ex2.java starts<---“);
System.out.println(“result is “ + result);
}
}
If you run this program, you will get the following output.
Exception in thread main
java.lang.ArithmeticException: / by zero
void ex2.main(java.lang.String[])
The program aborts if there is exception. This is ArithmeticException
. The great thing about it is that Java is highly object oriented and converts exceptions into objects. Java also provides some nice ways to handle these exceptions (objects). Let us study it in detail.
There are two types of exceptions. The first one represents error. These are hard situations and lead to abrupt termination of the program. Also, these are unrecoverable exceptions. A table describing various types of error is given in Section 19.8. Exceptions of second type are not so hard. They can be handled properly. Here program is not required to terminate immediately. Of course, we are required to code using rules of the game.
Package java.lang
defines a class Throwable
. This class has two sub-classes namely Error
and Exception
. Errors or exception occurring in the programs are objects of these classes.
Figure 19.1 Illustrates hierarchy of exception classes.
Figure 19.1 Hierarchy of Exceptions
Exceptions can be divided in two groups, runtime exceptions and non-runtime exception. Runtime exceptions occur within the Java runtime system. The examples are the following:
Java has defined a class RuntimeException
which acts as super-class for all individual runtime error classes. When we write methods, we need not catch or specify these exceptions. Hence, they can be termed as “unchecked exceptions”. The name is somewhat misleading as the JVM does check for these exceptions.
The other exceptions are those occurring in our code. Consider a case of exceptions that occur during input/output. The compiler ensures that we either catch or specify them. That is why they are called “checked exceptions”. It is possible that we may forget putting “try
block” around critical code, which is likely to produce say IOException. The compiler will refuse to compile the code. It will give the following error message.
unreported exception java.io.IOException; must be caught or declared to be thrown
If we add words throws Exception
to any method, it will compile without giving any error message.
Java offers an elegant solution to exception handling. It provides two constructs, try and catch. A try construct consists of keyword try
followed by block. (Block is a group of statements enclosed in curly brackets.) We will term this block as try block.
The code which is likely to produce exception is kept in this block. This is followed by catch construct. It consists of keyword catch
followed exception parameter (in round brackets) followed by a block. We will term this block as catch block. When executing code from try block raises an exception, the control is handed over to catch block. After this block ends, the control goes to next sentence in the program. Please note that the control does not go to try block again (see Program 19.2).
Problem: Write a program to illustrate try–catch action.
Solution: See Program 19.2.
PROGRAM 19.2 Try–Catch demo
// ex21.java
class ex21
{ public static void main (String args [])
{ int num = 20;
int den = 0 ;
int result=0;
System.out.println(“--->ex21.java starts<---“);
try {
result = num / den ;
System.out.println(“Just for test”);
}
catch(Exception e)
{ System.out.println(“Exception is caught”);
}
System.out.println(“result is “ + result);
}
}
If you run this program, you will get the following output.
Output
--->ex21.java starts<---
Exception is caught
result is 0
All the aforementioned points can be verified from the output. Note the absence of string
Just for test
in the output.
These actions are shown pictorially in Figure 19.2.
Figure 19.2 try–catch mechanism
Let us see a small program.
Problem: Write a program to demonstrate NullPointerException.
Solution: See Program 19.3.
PROGRAM 19.3 NullPointerException
// ex31.java
class ex31
{ public static void main (String args [])
{ int j =0;
String str ="welcome" ;
System.out.println("<---ex31.java--->");
try {
str = null;
j = str.length();
}
catch( NullPointerException e)
{ System.out.println("Exception is caught");
System.out.println(e.toString());
}
System.out.println("last line of the program");
}
}
If you run this program, you will get the following output.
Output
<---ex31.java--->
Exception is caught
java.lang.NullPointerException
last line of the program
One more program in Section 19.8 illustrates the NumberFormatException.
Remember the proverb “a stitch in time saves nine”. Some programmers may bypass the mechanism of checked exception. The compiler will not issue a warning. But such shortcuts may prove disastrous in the long range. When you write a method which has many statements throwing different exceptions, the code fails to compile. You get the following message.
“unreported exception java.io.IOException; must be caught or
declared to be thrown”.
There is a tendency to add throws Exception. The program compiles without any objection. But the program may fail when exception is thrown and we will have no chance to recover. In a professional application, this will not be acceptable.
finally
As an extension to try and catch, Java offers another facility in terms of keyword finally
. If we place a block labelled as finally
, just after the catch block, it will always be executed. Let us see its action in a program.
Problem: Write a program to illustrate keyword finally
.
Solution: See Program 19.4.
PROGRAM 19.4 Keyword finally
// ex23.java
class ex23
{ public static void main (String args [])
int den = 0 ;
int result=0;
System.out.println(“--->ex23.java starts<---”);
try {
result = num / den ;
System.out.println(“Just for test”);
}
catch(Exception e)
{ System.out.println(“Exception is caught”);
}
finally
{ System.out.println(
“All resources may be released here”);
}
System.out.println(“result is “ + result);
}
}
If you run this program, you will get the following output.
Output
--->ex23.java starts<---
Exception is caught
All resources may be released here
result is 0
Note that the catch block is executed followed by finally block. Afterwards, the control goes to next statement after finally
. Hence, the line “result is 0” appears in the output.
In the aforementioned program, if we change the denominator to 20, there will be no exception. As stated earlier, finally
block will still be executed. You can see the program ex23a.java
in Section 19.8.. You will notice that finally
block is executed when catch block is not.
Throw
StatementSo far we have only seen exception objects being generated because of some peculiarity in our code. Java allows us to define our own exceptions. It is called user-defined exception. For this, we must define a sub-class of Exception
. The throw
statement is used to throw the object of type exception.
Let us take a simple program from banking. One wants to withdraw money from an account. Naturally, for the operation to succeed, balance has to be greater than withdrawal. If someone tries to withdraw more than the balance there should be exception. Let us name it as insufficient balance.
See the following program.
Problem: Write a program to show that a new exception class can be defined.
Solution: Let us take a simple program from banking. We will define a class IBException
(IB = Insufficient Balance). See Program 19.5.
PROGRAM 19.5 Insufficient Balance Exception
// ex5a.java
class IBException extends Exception
{ public String toString()
{ return ("Transaction denied
" +"Insufficient balance");
}
} ;
class ex5a
{ public static void main (String args []) throws IBException
{ int balance = 20;
int withdraw = 30 ;
int result;
System.out.println("<---ex5a.java starts--->");
try
{ result = balance - withdraw ;
if (result < 0) throw new IBException() ;
balance = result;
System.out.println("balance is " + balance);
}
catch (IBException e)
{ System.out.println(e.toString());
}
}
}
If you compile this program, you will get the following output.
Output
<---ex5a.java starts--->
Transaction denied
Insufficient balance
Well the action on exception was very simple in this case. In real-life situation, action that is more appropriate will be required. If it is an ATM rather than a bank, an alarm in watchman’s cabin may be sounded.
Java allows multiple catch blocks after a try bloc. Any given code is likely to raise different possible exceptions. The action in response cannot be easily unified. For clarity of code, we should use different catch blocks for each exception.
When an exception occurs, the system tries to match with the type of exception one by one. When it finds a suitably matching catch block, system executes this block. Any further catch blocks are ignored.
Let us study this by a suitable example.
Problem: Write a program to demonstrate multiple catch blocks.
Solution: See Program 19.6.
PROGRAM 19.6 Multiple Catch Blocks I
// ex43.java
class ex43
{ public static void main (String args [])
{ int A[] ={0,1,2};
int j,k = 0 ;
String str ="welcome" ;
System.out.println("<---ex43.java--->");
try {
str = null; // note 1
j = str.length();
System.out.println("string length : "+ j) ;
k=5 ;
A[k]=0;
System.out.println(A[k]);
}
catch( NullPointerException e)
{ System.out.println("Exception is caught");
System.out.println(e.toString());
}
catch(ArrayIndexOutOfBoundsException e)
{ System.out.println("Exception is caught");
System.out.println(e.toString());
}
}
}
If you run this program, you will get the following output.
Output
<---ex43.java--->
Exception is caught
java.lang.NullPointerException
If you comment out line marked note 1, you will get the following output.
Output
<---ex43.java--->
string length : 7
Exception is caught
java.lang.ArrayIndexOutOfBoundsException: 5
When we write multiple catch blocks, the exception classes should be independent. If not, they should be properly structured. Let us study the following program before discussing the same.
Problem: Write a program to demonstrate unstructured multiple catch blocks.
Solution: See Program 19.7.
PROGRAM 19.7 Multiple Catch Blocks II
// ex42.java
class ex42
{ public static void main (String args [])
{ int A[] ={0,1,2};
int k = 0 ;
System.out.println("<---ex42.java--->");
try { k=5 ;
A[k]=0;
System.out.println(A[k]);
}
catch(Exception e)
{
}
catch(ArrayIndexOutOfBoundsException e)
{ System.out.println("Exception is caught");
System.out.println(e.toString());
}
System.out.println("last line of the program");
}
}
If you run this program, you will get the following compilation error.
Output
Compiling javac
ex42.java ex42.java:14: exception java.lang.ArrayIndexOutOfBoundsException has already
bee
n caught
catch(ArrayIndexOutOfBoundsException e)
^
1 error
press any key to continue
Please note the following points:
ArrayIndexOutOfBoundsException is a derivative (sub-subclass) of class Exception. We have stated a rule that exceptions are matched sequentially. Though Exception matches ArrayIndexOutOfBoundsException, such an exception clause will never get executed because exception is caught by earlier catch block. Hence, Java flags it as compilation error.
It is possible for Java developers to ignore such a case, but in certain circumstances, it can mar the real and correct action. This will reduce the quality of a program and also introduce bugs. Hence, this strictness on the part of Java should be appreciated.
After catch block, control flows out to the statement after
try
block. We have not coded any action here. You will appreciate the example if you consider an ATM in place of a bank counter.
finally
Problem: Write a program to show that clause finally
is executed even when there is no exception.
Solution: See Program 19.8.
PROGRAM 19.8 Clause finally
// ex23a.java
class ex23a
{ public static void main (String args [])
{ int num = 20;
int den = 20 ;
int result=0;
System.out.println("--->ex23a.java starts<---");
try {
result = num / den ;
System.out.println("Just for test");
}
catch(Exception e)
{ System.out.println("Exception is caught");
}
finally
{ System.out.println(
"All resources may be released here");
}
System.out.println("result is " + result);
}
}
If you run this program, you will get the following output.
Output
--->ex23a.java starts<---
Just for test
All resources may be released here
result is 1
Earlier, in chapter on Wrapper classes, we studied a method parseByte(String str)
which returns the byte equivalent of number contained in the string specified by str. It assumes radix 10. This throws NumberFormatException. The reason is that not every string can conforms to a number.
Problem: Write a program to demonstrate NumberFormatException.
Solution: See Program 19.9.
PROGRAM 19.9 NumberFormatException I
// ex35.java
class ex35
{ public static void main (String args [])
{ byte num ;
System.out.println("<---ex35.java--->");
num = Byte.parseByte("XY");
System.out.println("num is " + num);
}
}
If you run this program, you will get the following error output.
Output
<---ex35.java--->
Exception in thread "main" java.lang.NumberFormatException:
For input string: "XY"
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Byte.parseByte(Unknown Source)
at java.lang.Byte.parseByte(Unknown Source)
at ex35.main(ex35.java:6)
Please note that string XY
does not represent a number in radix 10. Therefore, there is an exception. Had the string been 23
, you would have got the following output.
<---ex35a.java--->
num is 23
In the aforementioned program, we have not caught the exception. It is known that parseByte()
is likely to throw the exception. Hence, a better idea is to use a catch
statement which writes a suitable comment like
”parameter is not a valid byte value.”
on the screen.
Java has large numbers of exceptions. They are organized in deep hierarchy. It is not possible to list all of them here. We have selected few common exceptions for ready reference. Readers are advised to refer to API specifications for complete details.
Table 19.1 lists the important sub-classes of class Exception
.
Table 19.1 Selected Sub-Classes of Class Exception
Table 19.2 describes the various kinds of checked and unchecked exceptions supported in Java. Please note that we have selected only few common exceptions.
Table 19.2 Summary of Checked and Unchecked Exceptions
Table 19.3 describes the various kinds of errors supported in Java.
Table 19.3 Summary of Errors
ArithmeticException
, ArrayIndexOutOfBoundsException
, catch
block, checked exceptions, class Throwable
, divide by zero exception, Exception
, finally, NullPointerException
, NumberFormatException
, throw
statement, throws
, tr
y block, unchecked exceptions, user-defined exception
try |
A try block must be followed by a catch block. Catch block need not be present if finally block is present |
finally |
When a finally block is present it is always executed irrespective of occurrence of exception |
finally |
A finally block is optional |
Exception class |
The root class of all the exception classes is the Exception class |
Instantiationexception |
Instantiation exception means an attempt to create an abstract class or interface |
Stack overflow | Stack overflow is an example of Runtime exception |
Runtime exception Exception |
An exception is an abnormal condition that disrupts normal program flow |
throw |
A throw statement causes an exception to be thrown |
throws |
A special clause called throws is used in method “definition” to indicate that a method may possibly throw an exception checked Exceptions Only runtime exceptions are checked exceptions, all others are unchecked exceptions. |
It may be noted that finally
keyword (and the facility thereof) is not present in C++.
finally
?throw
and throws
.IndexOutOfBoundsException
.NullPointerException
.StringIndexOutOfBoundsException
.**********************************************************
// ex37.java
class ex37
{ public static void main (String args [])
{ byte num = 20;
System.out.println("<---ex37.java starts--->");
try {
num = Byte.parseByte("128");
}
catch(Exception e) {
System.out.println("Exception is caught");
System.out.println(e);
};
System.out.println("num is " + num);
**********************************************************
}
}
**********************************************************
// ex52.java
class ex52
{
public static void main (String args [ ])
{
try
{
double x = 0.0;
throw (new Exception ("Thrown")) ;
//return ; Note 1
}
catch (Exception e)
{
System.out.println("Exception caught");
return ;
}
finally
{ System.out.println("***finally***"); }
}
}
**********************************************************
**********************************************************
// ex3a.java
class E extends Exception
{ } ;
class ex3a
{ public static void main (String args [])
{ int balance = 20;
int withdraw = 10 ;
int result;
System.out.println(“--->ex3a.java starts<---“);
result = balance - withdraw ;
if (result < 0) throw new E() ;
balance = result;
System.out.println(“balance is “ + balance);
}
}
**********************************************************
18.116.12.11