Exception Handling In Java Using Try-Catch And Finally

Exception Handling In Java Using Try-Catch And Finally
Exception Handling In Java Using Try-Catch And Finally

Introduction

In a perfect world, end-users would never enter data incorrectly. Files they wish to open would always exist. And programming would never have flaws. So far, we’ve primarily presented code as if we lived in a world where everything is fine. Now it’s time to look at the techniques for dealing with insufficient data and faulty code in the real world.

In exceptional cases, such as when flawed input data attempts to crash the program, Java uses a type of error trapping known as exception handling. This blog unfolds the magic of exception handling in Java.

So, let’s get started without further ado.

Keywords used in Exception Handling in Java

The five main clauses in exception handling are:

  • throw – raises an exception 
  • throws – reports exception 
  • try – monitors exception 
  • catch – handles the exception 
  • finally – finally can be the last block in the method that executes. In both normal and abnormal termination of the program execution.

Exceptions that can be handled using Exception Handling 

All exceptions descend from the Throwable parent class. But the hierarchy quickly divides into two branches: Error and Exception.

An essential element of Exception handling in Java is the Exception hierarchy. The Exception hierarchy is further divided into two branches:

  • Exceptions that are derived from RuntimeException
  • Exceptions that are not derived from RuntimeException

The general rule is: A RuntimeException happens because the programmer made a programming error. Any other exception occurs because some other thing, such as an I/O error, happened. The compiler checks for exceptional handlers for all the checked or compile-time exceptions. 

Inside the Java run-time system, the Error hierarchy defines internal errors and resource exhaust situations. A program should never throw this type of object. If an internal error occurs, a programmer has no choice but to warn the user and manually exit the program. These are highly uncommon circumstances.

Thus Exceptions are recoverable and can be handled by exception handling techniques, whereas Errors are irrecoverable and lead to abnormal termination of the program.

An Overview of Exception Handling in Java

An exception object in the Java programming language is always an instance of a Throwable-derived class. 

Missed out the basics of exception or looking to revisit the fundamental concepts, don’t worry!

Coding Ninjas has got you covered with a basic introduction to exceptions, their type, and hierarchy.

“The main goal of exception handling in Java is to transfer the control from where the error occurred to an error handler that can manage the situation.”

Suppose a Java program encounters an error while it is running. The programmer wants his code to react appropriately. If an operation fails due to an error, the program should either: 

  • Return to a safe state and allow the user to execute subsequent instructions; or 
  • Allow the user to save all work and manually end the program

Exception handling in Java involves three operations:

1. Declaring Checked Exceptions

A Java method must declare the types of checked exceptions it may throw, using the keyword “throws” in its signature.

For example, consider the declaration of the below-given method. After the throws keyword, the name of the potential exceptions is mentioned that the program may encounter during execution.

public void TestThrows() throws Exception1, Exception2 {...}

2. Throwing an exception

A program can throw an exception if it encounters a situation it cannot handle using the keyword “throw”. In other words, When a Java program encounters an abnormal situation, the method having the incorrect code should create an appropriate exception object and throw it to the JVM using the below statement. 

public void TestThrow() throws Exception1, Exception2
{
// Exception1 occurs
   if ( ... ) throw new Exception1(...);   
// construct an Exception1 object and throw to JVM

   // Exception2 occurs
   if ( ... ) throw new Exception2(...);   
// construct an Exception2 object and throw to JVM
}

Note: The keyword to declare the exception in the method’s signature is “throws”. And the keyword to throw an exception object within the method’s body is “throw”.

3. Catching an exception

When a method throws an exception, the JVM looks for a matching exception handler in the call stack. Each exception handler is limited to one type of exception. An exception handler that can handle a given class can also handle its subclasses. The program ends if no exception handler is found in the call stack.

For example, suppose a method method1() declares that it may throw Exception1 and Exception2 in its signature, as follows:

public void method1() throws Exception1, Exception2 { ...... }

There are two ways in which we can use method1 in our program.

1. Via a call to method1() inside a try-catch or try-catch-finally as given below. 

public void method2() 
{  // no exception declared
   try
{
      // uses method1() which declares Exception1 & Exception2
      method1();
   	} 
catch (Exception1 ex) {
      // Exception handler for Exception1
} 
catch (Exception2 ex} {
      // Exception handler for Exception2
} 
}

2. If method2(), which calls method1(), does not want to handle exceptions with a try-catch, it can specify these exceptions to be thrown up the call stack as follows.

public void method2() throws Exception1, Exception2 
{   
// for the higher-level method to handle

// uses method1() which declares "throws Exception1, Exception2"
   method1();   // no need for try-catch

}

Using try-catch

The first step in creating an exception handler is to use a try block to enclose any code that might throw an exception.

 A try block looks something like this in general:

try {
    code
}
catch and finally blocks

Multiple catch clauses

Exception handlers can be associated by placing one or more catch blocks after the try block. The code inside the catch block is executed when the exception handler is invoked.

try {

} catch (ExceptionType name) {

} catch (ExceptionType name) {

}
  • Each catch block is an exception handler that handles the type of exception indicated by its argument. 
  • The parameter must be the name of a class that inherits from the Throwable class and indicates the type of exception that the handler can handle. 
  • The exception can be referred to by name in the handler.
  • When the exception handler is the first in the call stack with an ExceptionType that matches the type of the exception raised, the runtime system calls it.

Example:

try {

} catch (IndexOutOfBoundsException e) 
{
    System.err.println("IndexOutOfBoundsException: " + e.getMessage());
} 
catch (IOException e) 
{
    System.err.println("Caught IOException: " + e.getMessage());
}

Displaying a Description of an Exception

To display the description of an exception, simply pass the exception as an argument to the print method.

The below-given program is an implementation of the above problem:

import java.io.*;

public class TestClass {
	public static void main(String args[])
    {
        try {
            String a = "Coding Ninjas"; // length is 13
            char c = a.charAt(14); // accessing 14th element
            System.out.println(c);
        }
        catch (StringIndexOutOfBoundsException e) {
  System.out.println("Displaying the description of Exception:"+e);
        }
        System.out.println("Execution Completed!!");
    }
}


Output
Displaying the description of Exception: java.lang.StringIndexOutOfBoundsException: String index out of range: 14
Execution Completed!!

Note: Exception handlers are capable of much more than simply printing error messages or terminating the program. They can utilise chained exceptions to accomplish error recovery. They can prompt the user to decide or propagate the error up to a higher-level handler.

Nested try statements

A situation may occur in which a part of a block causes one error, and the complete block causes another error. Exception handlers must be nested in such cases. 

In the same manner, we can employ a try block within a try block in Java. The context of an exception is pushed into a stack each time a try statement is entered.

An example of nested try blocks is shown below.

Example1: To handle an ArithmeticException, an inner try block is used in this example. The outer try block then handles the ArrayIndexOutOfBoundsException.

import java.io.*;
class TestClass {
	public static void main(String args[])
    {
        // Outer try block
        try {
  
           int a[] = { 1, 2, 3, 4, 5, 6, 7 };
  
            // printing element at index 7 i.e out 
            System.out.println(a[7]);
  
            // inner try block
            try {
  
                // division by zero
                int x = a[2] / 0;
            }
            catch (ArithmeticException e2) 
            {
                System.out.println("Arithmetic Exception encountered!!");
            }
        }
        catch (ArrayIndexOutOfBoundsException e1) 
        {
            System.out.println("ArrayIndexOutOfBounds Exception encountered!!");
            System.out.println("Catch method of outer try block implemented!!");
        }
    }
}




Output
ArrayIndexOutOfBounds Exception encountered!!
Catch method of outer try block implemented!!

  • If a try block does not have a catch block for a specific exception, the catch block of the parent block is searched for that exception, and if a match is found, the catch block of the parent is executed.
  • If none of the catch blocks catches the exception, the Java run-time system will handle it and display a system-generated message.

Example2: Another example of how the nested try block works can be seen here. Inside the body of the parent try block, you can see two try-catch blocks.

import java.io.*;
public class TestClass {
	public static void main(String args[]){
		 //Parent try block
	     try{
	    	//Child try block1
	         try{
	            System.out.println("Inside block1");
	            //Divide by zero exception........
	            int b =45/0;
	         }
	         catch(ArithmeticException e1){
	            System.out.println("Exception: e1");
	         }
	         //Child try block2
	         try{
	            System.out.println("Inside block2");
	            //Divide by zero exception again........
	            int b =45/0;
	         }
	         catch(ArrayIndexOutOfBoundsException e2){
	            System.out.println("Exception: e2");
	         }
	    }
	    catch(ArithmeticException e3){
	    	 System.out.println("Arithmetic Exception");
	         System.out.println("Inside parent's catch-1 block");
	    }
	    catch(ArrayIndexOutOfBoundsException e4){
	    	System.out.println("ArrayIndexOutOfBoundsException");
	         System.out.println("Inside parent's catch-2 block");
	    }
	    catch(Exception e5){
	    	System.out.println("Exception");
	         System.out.println("Inside parent's catch-3 block");
	    }
	System.out.println("Ending the parent try-catch block.......");
	  }
	}


Output
Inside block1
Exception: e1
Inside block2
Arithmetic Exception
Inside parent's catch-1 block
Ending the parent try-catch block.......

  • Child try-catch block1:  Integer divide by zero caused an ArithmeticException since the catch of block1 is handling ArithmeticException “Exception: e1” displayed.
  • Child try-catch block2: ArithmeticException occurred again, but block 2’s catch only handles ArrayIndexOutOfBoundsException, so control jumps to the parent try-catch body and looks for the ArithmeticException catch handler in parent’s catch block. 
  • The message “Inside parent try block” appears because the catch of the parent’s try block handles this exception with a generic Exception handler that handles all exceptions.
  • Parent try Catch block: In this case, there was no exception. Hence the message “Ending the parent try-catch block…….” appeared.

Need more insights about the try Block, you can refer to the official java documentation here.

Control flow in try-catch or try-catch-finally

The flow control in all the various combinations of try, catch, and finally, blocks are explained below:

1. Exception occurs in the try block and handled in the catch block

  • If a statement in the try block throws an exception, the rest of the try block is skipped, and control is passed to the catch block. 
  • When the catch block is completed, the control will be transferred to the finally block if it is present in the code, and then the rest of the program will be executed.

Program:

import java.io.*;
public class TestClass 
    {
	public static void main (String[] args){
        int[] arr = new int[7];
        try
        {
            int i = arr[7];
            // this statement will not be executed
            // as exception is raised by above statement
            System.out.println("Inside try block");
        }
        catch(ArrayIndexOutOfBoundsException ex)
        {
            System.out.println("Inside catch block!!");
        }
        finally
        {
            System.out.println("Inside finally block!!");
        }
        // rest of the program will be executed
        System.out.println("Outside try-catch-finally clause");
    }
}


Output
Inside catch block!!
Inside finally block!!
Outside try-catch-finally clause

2. Exception occurred in try-block is not handled in catch block:

In certain circumstances, the default handler is called. If there is a final block, it will be executed first, followed by the default handler.

Program:

import java.io.*;
public class TestClass {
	public static void main (String[] args)
    {
        int[] arr = new int[7];
        try
        {
            int i = arr[7];
            // this statement will not execute
            // as exception is raised by above statement
            System.out.println("Inside try block!!");
        }
        catch(NullPointerException ex)
        {
            System.out.println("Inside catch block!!");
        }
         
        finally
        {
            System.out.println("Inside finally block!!");
        }
        // rest of the program will not execute
        System.out.println("Outside try-catch-finally clause");
    }
}


Output
Inside finally block!!
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 7 out of bounds for length 7
	at TestClass.main(TestClass.java:8)

3. Exception doesn’t occur in try-block:

In this situation, the catch block is never executed because it is only supposed to be executed when an exception occurs. If a final block exists, it will be executed before the rest of the program.

Programme:

import java.io.*;
public class TestClass {
	public static void main (String[] args)
    {
       try
       {	
    	   String str = "123";
           int num = Integer.parseInt(str);
           // this statement will execute
        // as no any exception is raised by above statement
        System.out.println("End of the try block!!");
       }catch(NumberFormatException ex)
       {
        System.out.println("Inside catch block");
       }
       finally
       {
    	   System.out.println("Inside finally block!!");
       }
       System.out.println("Outside try-catch-finally clause");
    }
}


Output
End of the try block!!
Inside finally block!!
Outside try-catch-finally clause

Using finally

When the try block exits, the finally block is always executed. Even if an unexpected exception occurs, the finally block is executed.

Important points regarding the finally block are given below:

  • The finally block is a crucial technique for reducing resource leaks.
  • While closing a file or recovering resources, we must place the code in a finally block to ensure the resource is always recovered.
  • In these cases, consider utilizing the try-with-resources statement, which automatically releases system resources when they are no longer required.

Refer to this code snippet from java documentation explaining the above utility:

static String readFirstLineFromFileWithFinallyBlock(String path)
                                                     throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(path));
    try {
        return br.readLine();
    } finally {
        br.close();
    }
}

In this example, a finally block has been used to ensure that a resource is closed, regardless of whether the try statement executes normally or is terminated abruptly. 

Frequently Asked Questions

What are the five keywords used in java exception handling?

Java exception handling uses five keywords, try, catch, throw, throws, and finally.

How are the exceptions handled in Java? Specify one method.

The most basic method of handling exceptions is try-catch. Put the code in the try block, and any Java exceptions the code throws will be caught by one or more catch blocks followed by the try block.

Which keyword is used to throw an exception?

The throws keyword is used to specify which exceptions a method can throw, whereas the throw keyword is used to throw an exception explicitly within a method or block of code.

Can we throw an exception manually?

Using the throw keyword, we can explicitly throw a user-defined or predefined exception. To explicitly throw an exception, we must first create the class and then use the throw keyword to throw its object.

Can we catch and throw the same exception in a program?

We can do things like this in the catch block and then rethrow the exception. As a result, a higher level is notified that a system exception has occurred.

Key Takeaways

This article is designed so that it is helpful for both beginners and those preparing for placements and other tests.

It is an integral part of the four blog series on Introduction to exceptions and exception handling in Java. This is the third part of the series, and it explains exception handling using try, catch, and finally keywords along with their flow control.

Here’s a step-by-step guide to help you get the most out of this series.

  • Part 1: Exceptions in Java: Hierarchy, Types and its Relation with Errors.
  • Part 2: Checked vs unchecked exceptions in detail, along with their key differences.
  • Part 4: Exception handling using throw and throws.

Learning is fun!

But, some of us have limited resources.

As an initiative towards “Knowledge for all”, Coding Ninjas has brought a few free courses. The free courses cover an essential level of programming so that each student or IT enthusiast is at least familiar with the basic programming concepts.

So, Gear up, and start exploring and build up your concepts.

Happy Learning!

By Vaishnavi Pandey