<< Previous Chapter | Next Chapter >> |
Exception Handling in Java:
Definition:
Exceptions are the way in java to indicate to a calling
method that an abnormal condition has occurred. In this chapter we will discuss
how to use exceptions appropriately in our programs and designs.
When a method encounters an abnormal condition (an exception condition)
that it can't handle itself, it may throw an exception. Throwing an exception is
like throwing a beeping, flashing red light that indicates there is a problem
that cannot be handled where it occurred.
Exceptions are caught by handlers positioned along the
thread's method invocation stack. If the calling method is not prepared to
catch the exception, it throws the exception up to its calling method and so
on. If one of the threads of your program throws an exception that isn't caught
by any along the method invocation stack, that thread will expire. When we
program in Java, we must ensure that the exception handlers are strategically written,
so our program will catch and handle all exceptions from which we want our
program to recover.
Exception
classes
In java exception are classes. When we an exception, we throw
an object. However we cannot throw just any object as an exception, only those
objects whose classes descend from Throwable class of java.lang package.
Throwable is a base class of entire family of exception handling classes,
declared in java.lang package.
There is a hierarchy of classes defined for exception
handling, it makes:
1.
Reusability
2.
No need to make exception from scratch.
Always for an exception the object should be the child of java.lang.Throwable
class.
At
high level there are two types of abnormal conditions in java, exception and
error.
But,
there is nothing like an error in java, only exception concept does exist. Only
word ‘error’ is used for some special conditions, those which are not possible
to handle, it means even after handling of such error the program will be
terminated.
There are two kind of exceptions – checked and unchecked.
Checked vs. unchecked exception:
1) Checked exceptions are known to the compiler whereas
unchecked exceptions are unknown to the compiler.
2) in case of checked exception the compiler forces the
programmer to provide handler in their program (try .. catch.. finally). For
example System.in.read() – this statement is not allowed to be written in our
program without handler because this method throws IOException.
Quick question – how compiler determines that which method to
force to be in handler?
Answer – compiler first check for unique existence of the
method and then look for “throws” keyword
in it. (Checked exceptions only).
e.g. public void read() throws IOException
Anything which is going outside JVM boundary will be checked
for handler. For example we take an umbrella for safety when we go outside our
home, we never use it inside.
All abnormal conditions which occur outside JVM boundary are
checked by JVM and known to the compiler.
e.g. database, network, File IO etc.
e.g. in System.in.read() – java sense that it may get some
wrong values from outside which might generate any abnormal condition, so
compiler checks for handler in it.
try block:
Quick question – why it is named as “try” not anything
else?
Answer – because it will try to catch your exception and
not give 100% guarantee that it will be caught.
Example:
Create a class Temp inside dev21century.exceptions package
package dev21centurynew.exceptions;
public class Temp {
public static void main(String
args[])
{
try{
int x = 10/0;
System.out.println("x = " + x);
}
catch(ArithmeticException
e)
{
e.printStackTrace();
}
}
}
Inside catch block we should not keep so much code, only put an error
message and if required, call same methods using recursion and prompt for value
again.
package
dev21century.exceptions;
public class Temp {
public static void main(String args[])
{
try {
int x = 10 / args.length;
System.out.println("x =" + x);
int z[] = new int[args.length];
z[1]
= 100;
}
catch (ArithmeticException
e) {
System.out.println(e);
}
}
}
Now, run the program with exactly 1command line argument, there is an
option in eclipse to supply command line arguments to the main() method:
Right click on Temp.java file and go to -> Run As -> Run
Configurations, click on Arguments tab and enter few values separated by new
line.Output will be as follows:
Just notice that the error message has been changed. As we are supplying
1 argument, the division by zero error is resolved, but now we are trying to
access the array of position 1 which is not allowed. No, the solution for this
problem is we can multiple catch blocks in a single try block as follows, in
such case at a time only one catch block will be executed also at a time 2
exceptions are not possible:
package
dev21century.exceptions;
public class Temp {
public static void main(String args[])
{
try {
int x = 10 / args.length;
System.out.println("x =" + x);
int z[] = new int[args.length];
z[1]
= 100;
}
catch (ArithmeticException
e) {
System.out.println(e);
}
catch
(ArrayIndexOutOfBoundsException e) {
System.out.println(e);
}
}
}
Now, supply more than one arguments and see the output as follows:
Output:
Quick Important question –main()
method receives a string array and called by operating system, so while calling
it what parameter the operating system sends to the method?
Answer –it actually passes a zero
length array (no size no data), in java we have option to create zero length
array.
e.g. String str[] = { }; OR
String str[] = new String[0];
Not only String but all datatypes are allowed here.
Generic Exception Handling: - Now,
suppose we have 25 statements in our program, and there are 25 possible
exceptions then instead of putting 25 catch blocks, we can a single catch block
with Exception class, this class is parent of all exception classes, this is an
example of up casting & dynamic
binding.Like this:
package
dev21century.exceptions;
public class Temp {
public static void main(String args[])
{
try {
int x = 10 / args.length;
System.out.println("x =" + x);
int z[] = new int[args.length];
z[1]
= 100;
}
catch (Exception e) {
System.out.println(e);
}
}
}
Now, try to run above program in both ways (with and without
parameters).
First put all 25 catch blocks and then put this generic one. There is
another way to have this with single catch block, but this is not preferred
always because if there is an exception at a particular line then rest all
lines will be ignored:
Note:when we have multiple catch blocks in a single
try block then the exception classes should be defined in parent child order,
which means only up casting is allowed not down casting.
package
dev21century.exceptions;
public class Temp {
public static void main(String args[]) {
try {
int x = 10 / args.length;
System.out.println("x
=" + x);
int z[] = new int[args.length];
z[1] = 100;
}
catch (Exception e) {
if(e instanceof
ArrayIndexOutOfBoundsException)
{
System.out.println("Array
Index exception.." + e);
}
else if(e instanceof
ArithmeticException)
{
System.out.println("Arithmetic
exception.." + e);
}
}
}
}
The better way to deal with such problems is to have multiple try
blocks, this way if there is any exception at a particular line rest all will
not be skipped. Also try to put similar type of statements in a single try
block. For example:
package
dev21century.exceptions;
public class Temp {
public static void main(String args[])
{
try {
int x = 10 / args.length;
System.out.println("x =" + x);
}
catch (ArithmeticException
e) {
System.out.println(e);
}
try{
int z[] = new int[args.length];
z[1]
= 100;
}
catch(ArrayIndexOutOfBoundsException
e)
{
System.out.println(e);
}
}
}
But, in above case we have to define multiple generic handlers. The
solution is using nested try block, for
example:
package
dev21century.exceptions;
public class Temp {
public static void main(String args[])
{
try{
try {
int x = 10 / args.length;
System.out.println("x =" + x);
}
catch (ArithmeticException
e) {
System.out.println(e);
}
try{
int z[] = new int[args.length];
z[1]
= 100;
}
catch(ArrayIndexOutOfBoundsException
e)
{
System.out.println(e);
}
}
catch(Exception e)
{
System.out.println(e);
}
}
}
Finally Block:
Characteristics of finally block:
- The finally is a block similar to the catch block, which always gets executed irrespective of exception occurred or not.
- Finally block is always executed.
- We can have a finally block without a catch block.
- Finally block is never used to catch an exception
- We can have only one finally block with one try block.
- Whenever we use a finally block with a catch block then it must be the last block.
- Why finally? – most of the time we have some closing stuffs after completion of tasks like database connection, IO, network connection etc.
Finally block does not have any arguments because technology wanted that
it must be executed always.
Syntax:
try{
Connection con = …..
}
Catch(Exception e)
{
//exception message
}
Finally
{
Con.close();
}
Another condition where finally is required:
package
dev21century.exceptions;
public class FinallyDemo {
static int show()
{
try{
return 10;
}
catch(Exception e)
{
System.out.println(e);
}
finally{
return 20;
}
}
public static void main(String
args[])
{
int r= show();
System.out.println("r =
" + r);
}
}
Output will be 20.
Here methods return rule is breaking, finally block will be executed
even if there is no exception, because finally is the block which must be
executed in any condition.
Quick Question – if exception
occurs then also will go to finally and continue then where the exception goes?
Answer – exception will be killed
automatically, finally will be execute and program will continue.
Quick Question - is
there any situation where finally will not be executed?
Answer – only one condition System.exit(0);
once this statement encounters the program execution will be immediately terminated,
and finally will not run.
Throw statement:
“throw”
is used to throw an exception explicitly. For example lets take this example,
where we will throw an exception if entered age is less than 18:
package
dev21century.exceptions;
public class Temp {
int age;
void get(int age)
{
if(age < 18)
{
try{
throw new
ArithmeticException("Less Age..");
}
catch(ArithmeticException
e)
{
System.out.println(e);
}
}
}
public static void main(String args[]) {
Temp temp = new Temp();
temp.get(12);
}
}
Output:
all
exception classes in java receives a String parameter.
Unchecked
exceptions are automatically forwarded in a calling chain. See this example:
package
dev21century.exceptions;
public class Temp {
void show()
{
int x= 10/0;
}
void display()
{
show();
}
void xyz()
{
display();
}
public static void main(String args[]) {
Temp temp = new Temp();
try{
temp.xyz();
}
catch(ArithmeticException
e)
{
System.out.println(e);
}
}
}
Output:
But this rule is not applicable for checked exceptions,
because JVM will not allow without handler in same method.
throws
statement:
a
throws keyword added in a method indicates that this method throws an
exception. It also indicates that, it will be mandatory for the calling method
to either a provide handler or use throws further when it calls the method which
throws an exception. “throws” is used to mark that a method may throw exception
for example we write beware of dogs in our gates, Or we add a tips in medicine
that keep in cool and dry place etc. also throws is not preferred way of
programming.
create
a java file ThrowsDemo.java inside dev21century.exceptions package:
package
dev21century.exceptions;
import
java.io.IOException;
class Throws {
int divide() throws
ArithmeticException, IOException
{
System.out.println("enter
value for x");
int x = System.in.read();
System.out.println("enter
value for y");
int y = System.in.read();
int z = x / y;
return z;
}
}
public class ThrowsDemo {
public static void main(String
args[])
{
Throws throws1 = new Throws();
int r = throws1.divide();
}
}
Above program
will give compiler error at line number 19, because we have called divide()
method without handler, because divide() method throws exceptions. Now, there two
ways to handle this issue - either provide handler in main method or add throws
in main method as well.
1st way:
package
dev21century.exceptions;
import
java.io.IOException;
import
java.util.Scanner;
class Throws {
int divide() throws
ArithmeticException, IOException
{
Scanner scanner = new Scanner(System.in);
System.out.println("enter
value for x");
int x = scanner.nextInt();
System.out.println("enter
value for y");
int y = scanner.nextInt();
int z = x / y;
return z;
}
}
public class ThrowsDemo {
public static void main(String
args[])
{
Throws throws1 = new Throws();
try {
int r =
throws1.divide();
System.out.println("result
is " + r);
}
catch
(ArithmeticException e) {
System.out.println(e);
}
catch (IOException e)
{
System.out.println(e);
}
}
}
Output:
2nd Way:
package
dev21century.exceptions;
import
java.io.IOException;
import
java.util.Scanner;
class Throws {
int divide() throws
ArithmeticException, IOException
{
Scanner scanner = new Scanner(System.in);
System.out.println("enter
value for x");
int x = scanner.nextInt();
System.out.println("enter
value for y");
int y = scanner.nextInt();
int z = x / y;
return z;
}
}
public class ThrowsDemo {
public static void main(String
args[]) throws ArithmeticException, IOException
{
Throws throws1 = new Throws();
int r =
throws1.divide();
System.out.println("result
is " + r);
}
}
Output:
Same as
above.
In second
way we are passing our exception to JVM because main method is called by JVM,
so always avoid such kinds of programming habit.
We can also forward the checked exceptions to the calling chain using
throws.
Note – never extend the Throwable class otherwise Exception or Error
properties will not ne inherited.
Custom Exceptions:
The custom
exceptions are user defined exceptions, which makes the debugging of our
program easy also we can prompt our appropriate message to the user on occurrence
of any exception.
Quick Question – custom exceptions are checked or unchecked?
Answer – it depends on parent, if parent exception is checked then
custom exception will be checked and vice versa.
Example:
Create a
file CustomExceptionDemo in dev21century.exceptions package:
package
dev21century.exceptions;
class AgeException
extends Exception
{
AgeException(String
s)
{
super(s);
}
}
public class
CustomExceptionDemo {
int age;
void get(int age) throws AgeException
{
if(age < 18)
{
throw new AgeException("Age must
be greater than 18.");
}
else
this.age = age;
}
public static void main(String[]
args) {
CustomExceptionDemo
customExceptionDemo = new CustomExceptionDemo();
try{
customExceptionDemo.get(15);
}
catch(AgeException e)
{
System.out.println(e);
e.printStackTrace();
}
}
}
Output:
If you
notice when print a String class object or Exception class object directly
through System.out.println() method then it prints the proper message, but for
other objects it prints some hexadecimal values. Why so?
This is
because the toString() method of Object class. When we print a string object,
it internally calls the toString method of that object. And in case of
Exception class, its parent overrides this method which returns the message in
string format. So, internally Throwable and Exception classes are implemented
like this:
package
dev21century.exceptions;
class Throwable extends Object
{
String
msg;
public String
toString()
{
return msg;
}
}
class Exception extends Throwable
{
Exception(String
msg)
{
this.msg = msg;
}
}
Only Throwable
class implements the toString() method not any other exception class. However we
can also override it in our exception classes:
package
dev21century.exceptions;
class AgeException
extends Exception
{
String
s;
AgeException(String
s)
{
//super(s);
this.s = s;
}
public String
toString()
{
return s;
}
}
public class
CustomExceptionDemo {
int age;
void get(int age) throws AgeException
{
if(age < 18)
{
throw new AgeException("Age must
be greater than 18.");
}
else
this.age = age;
}
public static void main(String[]
args) {
CustomExceptionDemo
customExceptionDemo = new CustomExceptionDemo();
try{
customExceptionDemo.get(15);
}
catch(AgeException e)
{
System.out.println(e);
e.printStackTrace();
}
}
}
Output:
In above program, instead of utilizing toString()
method of Throwable class we have overridden it in our exception class itself.
<< Previous Chapter | Next Chapter >> |
No comments:
Post a Comment