Code360 powered by Coding Ninjas X Naukri.com. Code360 powered by Coding Ninjas X Naukri.com
Table of contents
1.
Introduction
2.
What is Exception in Java?
3.
What is Exception Handling in Java?
4.
Hierarchy of Java Exception Classes
5.
Types of Java Exceptions
6.
Keywords used in Exception Handling in Java
7.
Exceptions that can be handled using Exception Handling 
8.
Exception handling in Java involves three operations:
8.1.
1. Declaring Checked Exceptions
8.2.
2. Throwing an exception
8.3.
3. Catching an exception
8.3.1.
1. Via a call to method1() inside a try-catch or try-catch-finally as given below. 
8.3.2.
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.
9.
Using try-catch
10.
Multiple catch clauses
11.
Displaying a Description of an Exception
11.1.
Java
12.
Nested try statements
12.1.
Java
12.2.
Java
13.
Control flow in try-catch or try-catch-finally
13.1.
1. Exception occurs in the try block and handled in the catch block
13.2.
Java
13.3.
2. Exception occurred in try-block is not handled in catch block:
13.4.
Java
13.5.
3. Exception doesn’t occur in try-block:
13.6.
Java
14.
Using finally
15.
Frequently Asked Questions
15.1.
What are the five keywords used in java exception handling?
15.2.
How are the exceptions handled in Java? Specify one method.
15.3.
Which keyword is used to throw an exception?
15.4.
Can we throw an exception manually?
15.5.
Can we catch and throw the same exception in a program?
16.
Conclusion
Last Updated: Sep 30, 2024
Hard

Exception Handling In Java

Introduction

Exception handling is a critical feature in Java that ensures the robustness and reliability of your applications. It provides a structured approach to managing runtime errors, allowing programs to respond gracefully to unexpected situations without crashing. By using Java's exception handling mechanisms, you can capture and address errors such as invalid input, network failures, and file operations issues, thereby enhancing user experience and maintaining system stability. In this blog, we will delve into the fundamentals of exception handling in Java, exploring key concepts such as try-catch blocks, throwing exceptions, and creating custom exceptions.

Exception Handling In Java Using Try-Catch And Finally

Must Read, Multithreading in java, Duck Number in Java

What is Exception in Java?

In Java, an exception is an event that disrupts the normal flow of a program’s execution. It represents an error or unexpected situation that occurs during runtime, such as attempting to divide by zero, accessing an out-of-bounds array element, or failing to open a file. When an exception occurs, Java creates an exception object that contains information about the error, including its type and the state of the program at the time of the error. Proper handling of exceptions is crucial to ensure that a program can recover from errors and continue running smoothly.

What is Exception Handling in Java?

Exception handling in Java is a mechanism that allows developers to manage runtime errors in a structured way. It involves using specific language constructs to catch exceptions, handle them, and ensure that the program can recover or exit gracefully. The primary constructs used in exception handling are try, catch, finally, and throw. By enclosing code that might generate exceptions in a try block and providing catch blocks to handle those exceptions, developers can prevent errors from causing program crashes and implement appropriate recovery strategies.

Hierarchy of Java Exception Classes

Java's exception handling framework is built around a class hierarchy that starts with the Throwable class. The hierarchy is structured as follows:

  • Throwable: The root class for all exceptions and errors.
    • Exception: Represents exceptions that a program might want to catch. It includes:
      • RuntimeException: Represents exceptions that occur during the program’s execution, which are unchecked and do not require explicit handling.
      • Checked Exceptions: Subclasses of Exception that are not subclasses of RuntimeException. They must be either caught or declared in the method signature using throws.
    • Error: Represents serious problems that a program typically should not try to handle, such as OutOfMemoryError and StackOverflowError.

Types of Java Exceptions

Java exceptions are categorized into several types:

  1. Checked Exceptions: These exceptions are checked at compile-time. The programmer must handle them using try-catch blocks or declare them using the throws keyword. Examples include IOException and SQLException.
  2. Unchecked Exceptions: These exceptions are not checked at compile-time and include RuntimeException and its subclasses. They often represent programming errors, such as NullPointerException and ArrayIndexOutOfBoundsException.
  3. Errors: These are serious issues that are not typically handled by programs. They include VirtualMachineError, OutOfMemoryError, and StackOverflowError. These usually indicate problems that are beyond the control of the program.

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.

Also see,  Swap Function in Java

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:

  • Java

Java

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!!");
   }
}
You can also try this code with Online Java Compiler
Run Code

Output

Displaying the description of Exception: java.lang.StringIndexOutOfBoundsException: String index out of range: 14
Execution Completed!!
You can also try this code with Online Java Compiler
Run Code

 

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.

  • Java

Java

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!!");
       }
   }
}
You can also try this code with Online Java Compiler
Run Code

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.

  • Java

Java

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.......");
}
}
You can also try this code with Online Java Compiler
Run Code

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:

  • Java

Java

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");
   }
}
You can also try this code with Online Java Compiler
Run Code

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:

  • Java

Java

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");
   }
}
You can also try this code with Online Java Compiler
Run Code

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.

Program:

  • Java

Java

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");
   }
}
You can also try this code with Online Java Compiler
Run Code

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. 

Must Read Static Blocks In Java and Hashcode Method in Java

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.

Conclusion

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

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.

Happy Learning!

Live masterclass