Java Exception Handling

In this tutorial, you will learn to handle exceptions in Java with the help of examples. To handle exceptions, we will use try...catch...finally blocks.

In the last tutorial, we learned about exceptions. Exceptions are unexpected events that occur during program execution.


Catching and handling exceptions

In Java, we use the exception handler components try, catch and finally blocks to handle exceptions.

To catch and handle an exception, we place the try...catch...finally block around the code that might generate an exception. The finally block is optional.

The syntax for try...catch...finally is:

try {
  // code
} catch (ExceptionType e) { 
  // catch block
} finally {
  // finally block
}

Java try...catch block

The code that might generate an exception is placed in the try block.

Every try block should be immediately followed by the catch or finally block. When an exception occurs, it is caught by the catch block that immediately follows it.

catch blocks cannot be used alone and must always be preceded by a try block.

Example 1: try...catch blocks

class Main {
  public static void main(String[] args) {

    try {
      int divideByZero = 5 / 0;
      System.out.println("Rest of code in try block");
    } catch (ArithmeticException e) {
      System.out.println("ArithmeticException => " + e.getMessage());
    }

  }
}

Output

ArithmeticException => / by zero

In the example,

  • We have divided a number by 0 inside the try block. This produces an ArithmeticException.
  • When the exception occurs, the program skips the rest of the code in the try block.
  • Here, we have created a catch block to handle ArithmeticException. Hence, the statements inside the catch block are executed.

If none of the statements in the try block generates an exception, the catch block is skipped.


Multiple Catch blocks

For each try block, there can be zero or more catch blocks.

The argument type of each catch block indicates the type of exception that can be handled by it. Multiple catch blocks allow us to handle each exception differently.

Example 2: Multiple catch blocks

class ListOfNumbers {
  public int[] arrayOfNumbers = new int[10];

  public void writeList() {

    try {
      arrayOfNumbers[10] = 11;
    } catch (NumberFormatException e1) {
      System.out.println("NumberFormatException => " + e1.getMessage());
    } catch (IndexOutOfBoundsException e2) {
      System.out.println("IndexOutOfBoundsException => " + e2.getMessage());
    }

  }
}

class Main {
  public static void main(String[] args) {
    ListOfNumbers list = new ListOfNumbers();
    list.writeList();
  }
}

Output

IndexOutOfBoundsException => Index 10 out of bounds for length 10

In this example, we have declared an array of integers arrayOfNumbers of size 10.

We know that an array index always starts from 0. So, when we try to assign a value to index 10, an IndexOutOfBoundsException occurs because the array bounds for arrayOfNumbers is 0 to 9.

When an exception occurs in the try block,

  • The exception is thrown to the first catch block. The first catch block does not handle an IndexOutOfBoundsException, so it is passed to the next catch block.
  • The second catch block in the above example is the appropriate exception handler because it handles an IndexOutOfBoundsException. Hence, it is executed.

Java finally block

For each try block, there can be only one finally block.

The finally block is optional. However, if defined, it is always executed (even if the exception doesn't occur).

If an exception occurs, it is executed after the try...catch block. If no exception occurs, it is executed after the try block.

The basic syntax of finally block is:

try {
  //code
} catch (ExceptionType1 e1) { 
  // catch block
} catch (ExceptionType1 e2) {
 // catch block
} finally {
  // finally block always executes
}

Example 3: finally block

class Main {
  public static void main(String[] args) {
    try {
      int divideByZero = 5 / 0;
    } catch (ArithmeticException e) {
      System.out.println("ArithmeticException => " + e.getMessage());
    } finally {
      System.out.println("Finally block is always executed");
    }
  }
}

Output

ArithmeticException => / by zero
Finally block is always executed

In this example, we have divided a number by 0. This throws an ArithmeticException which is caught by the catch block. The finally block always executes.

Having a finally block is considered a good practice. It is because it includes important cleanup code such as:

  • code that might have been accidentally skipped by return, continue or break statements
  • closing a file or connection

We have mentioned that finally always executes and that is usually the case. However, there are some cases when a finally block does not execute:

  • Use of System.exit() method
  • An exception occurs in the finally block
  • The death of a thread

Example 4: try, catch and finally blocks

Let’s take an example where we try to create a new file using FileWriter and write data to it using PrintWriter.

import java.io.*;

class ListOfNumbers {
  private int[] list = new int[10];

  public ListOfNumbers() {
    // storing integer values in the list array
    for (int i = 0; i < 10; i++) {
      list[i] = i;
    } 	
  }

}

  public void writeList() {
    PrintWriter out = null;

    try {
      System.out.println("Entering try statement");

      // creating a new file OutputFile.txt
      out = new PrintWriter(new FileWriter("OutputFile.txt"));

      // writing values from list array to the new created file
      for (int i = 0; i < 10; i++) {
        out.println("Value at: " + i + " = " + list[i]);
      }
    } catch (IndexOutOfBoundsException e1) {
      System.out.println("IndexOutOfBoundsException => " + e1.getMessage());
    } catch (IOException e2) {
      System.out.println("IOException => " + e2.getMessage());
    } finally {
      // checking if PrintWriter has been opened
      if (out != null) {
        System.out.println("Closing PrintWriter");
        out.close();
      } else {
        System.out.println("PrintWriter not open");
      }
    }

  }
}

class Main {
  public static void main(String[] args) {
    ListOfNumbers list = new ListOfNumbers();
    list.writeList();
  }
}

When you run this program, there are two possibilities that may occur:

  1. An exception occurs in the try block
  2. The try block executes normally

An exception can occur while creating new FileWriter. It throws an IOException if the file specified cannot be created or written to.

When an exception occurs, we will get the following output.

Entering try statement
IOException => OutputFile.txt
PrintWriter not open

When exception doesn't occur and the try block executes normally, we will get the following output.

Entering try statement
Closing PrintWriter

An OutputFile.txt is created and will have the following content:

Value at: 0 = 0
Value at: 1 = 1
Value at: 2 = 2
Value at: 3 = 3
Value at: 4 = 4
Value at: 5 = 5
Value at: 6 = 6
Value at: 7 = 7
Value at: 8 = 8
Value at: 9 = 9

Working of try...catch...finally in Detail

Let's try to understand the flow of exception handling in detail with the help of above example.

Working of try...catch...finally in Java

The above figure describes the flow of program execution when an exception occurs while creating a new FileWriter.

  • To get to the method where the exception occurs, the main method calls the writeList() method which then calls the FileWriter() method to create a new OutputFile.txt file.
  • When an exception occurs, the runtime system skips the rest of the code in the try block.
  • It starts searching through the call stack in reverse order to find an appropriate exception handler.
  • Here, FileWriter does not have an exception handler, so runtime system checks the next method in the call stack i.e writeList.
  • The writeList method has two exception handlers: one that handles IndexOutOfBoundsException and another that handles IOException.
  • The system then goes through these handlers in sequential order.
  • The first handler in this example handles IndexOutOfBoundsException. This does not match the IOException thrown by the try block.
  • So, the next handler is checked which is the IOException handler. This matches the type of exception thrown so the code in the catch block is executed.
  • After the exception handler executes, the finally block is executed.
  • In this scenario, since an exception occurred in the FileWriter, the PrintWriter object out was never opened and does not need to be closed.

Now, let us suppose that the exception doesn’t occur while running this program and the try block executes normally. An OutputFile.txt is created and written to in this case.

As we know, the finally block is executed regardless of the exception handling. Since no exception occurred, the PrintWriter is open and needs to be closed. This is done by out.close() statement in the finally block.


Catching Multiple Exceptions

From Java SE 7 and later, we can now catch more than one type of exception with one catch block.

This reduces code duplication and increases code simplicity and efficiency.

Each exception type that can be handled by the catch block is separated using a vertical bar |.

Its syntax is:

try {
  // code
} catch (ExceptionType1 | Exceptiontype2 ex) { 
  // catch block
}

Visit Java catching multiple exceptions to learn more.


The try-with-resources statement

The try-with-resources statement is a try statement that has one or more resource declarations.

Its syntax is:

try (resource declaration) {
  // use of the resource
} catch (ExceptionType e1) {
  // catch block
}

The resource is an object to be closed at the end of the program. It must be declared and initialized in the try statement.

Let’s take an example.

try (PrintWriter out = new PrintWriter(new FileWriter(“OutputFile.txt”)) {
  // use of the resource
}

The try-with-resources statement is also referred to as automatic resource management. This statement automatically closes all the resources at the end of the statement.

To learn about it in detail, visit Java try-with-resources statement.