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[]) throwsArithmeticException, 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 = newCustomExceptionDemo();
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 = newCustomExceptionDemo();
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.
No comments:
Post a Comment