Exceptions in java


Reading time: 45 minutes

Java has a great and powerful mechanism to handle the exceptions so that normal flow of the application can be maintained. We explore the various types of exceptions, how it is handled by JVM and how it can be handled by users in a custom procedure.

What are Exceptions ?

An exception (or exceptional event) is a problem that arises during the execution of a program. When an Exception occurs the normal flow of the program is disrupted and the program/Application terminates abnormally, which is not recommended, therefore, these exceptions are to be handled.

Note : Errors Vs Exceptions
Errors : An Error indicates serious problem that a reasonable application should not try to catch.
Exceptions : Exception indicates conditions that a reasonable application might try to catch.

Exception Hierarchy

java-heirarchy

All exception and errors types are sub classes of class Throwable, which is base class of hierarchy.One branch is headed by Exception. This class is used for exceptional conditions that user programs should catch. NullPointerException is an example of such an exception.Another branch,Error are used by the Java run-time system(JVM) to indicate errors having to do with the run-time environment itself(JRE). StackOverflowError is an example of such an error.

a. Exception class is for exceptional conditions that program should catch. This class is extended to create user specific exception classes.
b. RuntimeException is a subclass of Exception. Exceptions under this class are automatically defined for programs.
c. 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.

An exception can occur for many different reasons. Following are some scenarios where an exception occurs :

  1. A user has entered an invalid data.
  2. A file that needs to be opened cannot be found.
  3. A network connection has been lost in the middle of communications or the JVM has run out of memory.

Some of these exceptions are caused by user error, others by programmer error, and others by physical resources that have failed in some manner.

Based on these, we have three categories of Exceptions. We need to understand them to know how exception handling works in Java :

1. Checked exceptions :

A checked exception is an exception that is checked (notified) by the compiler at compilation-time, these are also called as compile time exceptions. These exceptions cannot simply be ignored, the programmer should take care of (handle) these exceptions.

For Example, if we use FileReader class in our program to read data from a file, if the file specified in its constructor doesn't exist, then a FileNotFoundException occurs, and the compiler prompts the programmer to handle the exception.

Example

import java.io.File;
import java.io.FileReader;

public class FilenotFound_Demo {

   public static void main(String args[]) {		
      File file = new File("E://file.txt");
      FileReader fr = new FileReader(file); 
   }
}

Output

C:\>javac FilenotFound_Demo.java
FilenotFound_Demo.java:8: error: unreported exception FileNotFoundException; must be caught or declared to be thrown
      FileReader fr = new FileReader(file);
                      ^
1 error

Note : Since the methods read() and close() of FileReader class throws IOException, we can observe that the compiler notifies to handle IOException, along with FileNotFoundException.

2. Unchecked exceptions :

An unchecked exception is an exception that occurs at the time of execution. These are also called as Runtime Exceptions. These include programming bugs, such as logic errors or improper use of an API. Runtime exceptions are ignored at the time of compilation.
For Example, if we have declared an array of size 5 in our program, and trying to call the 6th element of the array then an ArrayIndexOutOfBoundsExceptionexception occurs.

Example :

public class Unchecked_Demo {
   
   public static void main(String args[]) {
      int num[] = {1, 2, 3, 4};
      System.out.println(num[5]);
   }
}

Output

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
	at Exceptions.Unchecked_Demo.main(Unchecked_Demo.java:8)

3. 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.

Exception Handling By Jvm

Default Exception Handling :

Whenever inside a method, if an exception has occurred, the method creates an Object known as Exception Object and hands it off to the run-time system(JVM). The exception object contains name and description of the exception, and current state of the program where exception has occurred. Creating the Exception Object and handling it to the run-time system is called throwing an Exception.There might be the list of the methods that had been called to get to the method where exception was occurred. This ordered list of the methods is called Call Stack.Now the following procedure will happen.

i. The run-time system searches the call stack to find the method that contains block of code that can handle the occurred exception. The block of the code is called Exception handler.

ii. The run-time system starts searching from the method in which exception occurred, proceeds through call stack in the reverse order in which methods were called.

iii. If it finds appropriate handler then it passes the occurred exception to it. Appropriate handler means the type of the exception object thrown matches the type of the exception object it can handle.

iv. If run-time system searches all the methods on call stack and couldn’t have found the appropriate handler then run-time system handover the Exception Object to default exception handler , which is part of run-time system. This handler prints the exception information in the following format and terminates program abnormally.

Exception in thread "xxx" Name of Exception : Description
... ...... ..  // Call Stack

See the below diagram to understand the flow of the call stack :
stack

Exception Handling By Programmer

Customized Exception Handling :

Java exception handling is managed via five keywords:
a. try
b. catch
c. throw
d. throws
e. finally.

Now, here is how the above keywords work :
Program statements that you think can raise 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 block) and handle it in some rational manner. System-generated exceptions are automatically thrown by the Java run-time system.

In other words, Try is used to guard a block of code in which exception may occur. This block of code is called guarded region. A catch statement involves declaring the type of exception you are trying to catch. If an exception occurs in guarded code, the catch block that follows the try is checked, if the type of exception that occured is listed in the catch block then the exception is handed over to the catch block which then handles it.
Now, 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.

Example of Using try and catch :

An exception will thrown by this following program as we are trying to divide a number by zero inside try block. The program control is transferred outside try block. Thus the line "This line will not be executed" is never parsed by the compiler. The exception thrown is handled in catch block. Once the exception is handled, the program control is continue with the next line in the program i.e after catch block. Thus the line "After exception is handled" is printed.

class Excp
{
 public static void main(String args[])
 {
  int a,b,c;
  try
  {
   a=0;
   b=10;
   c=b/a;
   System.out.println("This line will not be executed");
  }
  catch(ArithmeticException e)
  {
   System.out.println("Divided by zero");
  }
  System.out.println("After exception is handled");
 }
}

Output

Divided by zero
After exception is handled

Multiple catch blocks :

A try block can be followed by multiple catch blocks. You can have any number of catch blocks after a single try block.If an exception occurs in the guarded code the exception is passed to the first catch block in the list. If the exception type of exception, matches with the first catch block it gets caught, if not the exception is passed down to the next catch block. This continue until the exception is caught or falls through all catches.

Example of Using Multiple catch blocks :

class Excep
{
 public static void main(String[] args)
 {
  try
  {
   int arr[]={1,2};
   arr[2]=3/0;
  }
  catch(ArithmeticException ae)
  {
   System.out.println("divide by zero");
  }
  catch(ArrayIndexOutOfBoundsException e)
  {
   System.out.println("array index out of bound exception");
  }
 }
}

Output :

divide by zero

Note - 1 : Although both ArrayIndexOutOfBoundsException and ArithmeticException occured, but since first catch is of Arithmetic Exception, It will be caught there and program control will be continued after the catch block.
Note - 2 : At a time, only one exception is processed and only one respective catch block is executed.

Nested try statement

try statement can be nested inside another block of try. Nested try block is used when a part of a block may cause one error while entire block may cause another error. In case if inner try block does not have a catch handler for a particular exception then the outer try catch block is checked for match.

Example of Using Nested try statement :

class Excep
{
 public static void main(String[] args)
 {
  try
  {
   int arr[]={5,0,1,2};
   try
   {
    int x=arr[3]/arr[1];
   }
   catch(ArithmeticException ae)
   {
    System.out.println("divide by zero");
   }
   arr[4]=3;
  }
  catch(ArrayIndexOutOfBoundsException e)
  {
   System.out.println("array index out of bound exception");
  }
 }
}

Output

divide by zero
array index out of bound exception

finally blocks :

  • Java finally block is a block that is used to execute important code such as closing connection, stream etc.
  • Java finally block is always executed whether exception is handled or not.
  • Java finally block follows try or catch block.
  • Finally block in java can be used to put "cleanup" code such as closing a file, closing connection etc.
  • For each try block there can be zero or more catch blocks, but only one finally block.
  • The finally block will not be executed if program exits(either by calling System.exit() or by causing a fatal error that causes the process to abort).

Example of Using finally block

public class TestFinallyBlock2{  
  public static void main(String args[]){  
  try{  
   int data=25/0;  
   System.out.println(data);  
  }  
  catch(ArithmeticException e){System.out.println(e);}  
  finally{System.out.println("finally block is always executed");}  
  System.out.println("rest of the code...");  
  }  
}  

Output

Output:Exception in thread main java.lang.ArithmeticException:/ by zero
       finally block is always executed
       rest of the code...

throw keyword

The Java throw keyword is used to explicitly throw an exception.We can throw either checked or unchecked exception in java by throw keyword. The throw keyword is mainly used to throw custom exception. We will see custom exceptions later.
The syntax of java throw keyword is given below.

throw exception;  

Example of Using throw keyword

In this example, we have created the validate method that takes integer value as a parameter. If the age is less than 18, we are throwing the ArithmeticException otherwise print a message welcome to vote.

public class TestThrow1{  
   static void validate(int age){  
     if(age<18)  
      throw new ArithmeticException("not valid");  
     else  
      System.out.println("welcome to vote");  
   }  
   public static void main(String args[]){  
      validate(13);  
      System.out.println("rest of the code...");  
  }  
}  

Output

Exception in thread main java.lang.ArithmeticException:not valid

throws keyword

The Java throws keyword is used to declare an exception. It gives an information to the programmer that there may occur an exception so it is better for the programmer to provide the exception handling code so that normal flow can be maintained.

Exception Handling is mainly used to handle the checked exceptions. If there occurs any unchecked exception such as NullPointerException, it is programmers fault that he is not performing check up before the code being used.

Syntax of java throws :

return_type method_name() throws exception_class_name{  
//method code  
}  

Example of Using throws keyword

Let's see the example of java throws clause which describes that checked exceptions can be propagated by throws keyword.

import java.io.IOException;  
class Testthrows1{  
  void m()throws IOException{  
    throw new IOException("device error");//checked exception  
  }  
  void n()throws IOException{  
    m();  
  }  
  void p(){  
   try{  
    n();  
   }catch(Exception e){System.out.println("exception handled");}  
  }  
  public static void main(String args[]){  
   Testthrows1 obj=new Testthrows1();  
   obj.p();  
   System.out.println("normal flow...");  
  }  
}  

Output

exception handled
normal flow...

Advantage of Java throws keyword

  • Now Checked Exception can be propagated (forwarded in call stack).
  • It provides information to the caller of the method about the exception.

Rule : If you are calling a method that declares an exception, you must either caught or declare the exception.

There are two cases :
Case-1 : You caught the exception i.e. handle the exception using try/catch.
Case-2 : You declare the exception i.e. specifying throws with the method.

Case-1 : You handle the exception :

In case you handle the exception, the code will be executed fine whether exception occurs during the program or not.

import java.io.*;  
class M{  
 void method()throws IOException{  
  throw new IOException("device error");  
 }  
}  
public class Testthrows2{  
   public static void main(String args[]){  
    try{  
     M m=new M();  
     m.method();  
    }catch(Exception e){System.out.println("exception handled");}     
  
    System.out.println("normal flow...");  
  }  
} 

Output

Output:exception handled
       normal flow...

Case-2 : You declare the exception

i. In case you declare the exception, if exception does not occur, the code will be executed fine.

ii. In case you declare the exception if exception occures, an exception will be thrown at runtime because throws does not handle the exception.

i. Program if exception does not occur :-

import java.io.*;  
class M{  
 void method()throws IOException{  
  System.out.println("device operation performed");  
 }  
}  
class Testthrows3{  
   public static void main(String args[])throws IOException{//declare exception  
     M m=new M();  
     m.method();  
  
    System.out.println("normal flow...");  
  }  
}  

Output :

device operation performed
       normal flow...

B. Program if exception occurs :-

import java.io.*;  
class M{  
 void method()throws IOException{  
  throw new IOException("device error");  
 }  
}  
class Testthrows4{  
   public static void main(String args[])throws IOException{//declare exception  
     M m=new M();  
     m.method();  
  
    System.out.println("normal flow...");  
  }  
}  

Output :

Runtime Exception

Important points to Remember :

  1. If you do not explicitly use the try catch blocks in your program, java will provide a default exception handler, which will print the exception details on the terminal, whenever exception occurs.
  2. Super class Throwable overrides toString() function, to display error message in form of string.
  3. While using multiple catch block, always make sure that sub-classes of Exception class comes before any of their super classes. Else you will get compile time error.
  4. In nested try catch, the inner try block uses its own catch block as well as catch block of the outer try, if required.
  5. Only the object of Throwable class or its subclasses can be thrown.