Skip to main content
Advertisement

8.2 try-catch and finally Blocks

The most fundamental and essential syntax for manually implementing exception handling in Java is the try-catch block. Instead of your program abruptly dying the moment an error occurs, Java provides this construct as a safety net, allowing you to gracefully evade or resolve the problem.

In this chapter, we will explore the structure and mechanics of the try-catch statement, and the purpose of the finally block.

1. Basic Structure of a try-catch

An exception handling try-catch construct is broadly divided into a try block(where code that might throw an exception is placed) and a catch block(which is dedicated to handling the exception if it occurs).

try {
// Code that might throw an exception is placed here.
// ...
} catch (Exception1 e1) {
// Code to execute if an Exception1 type error occurs
} catch (Exception2 e2) {
// Code to execute if an Exception2 type error occurs
}
  • try block: A monitored zone where Java checks if the code executes normally.
  • catch block: If an exception "blows up" (throw) inside the try, Java instantly halts the execution within that try and jumps to the code inside the matching catch block to manage the situation. The reference variable in the parentheses (like e1, e2) receives the generated exception object containing detailed information about the error.

✍️ Example: Division by Zero (ArithmeticException)

In Java, since dividing a number mathematically by 0 is impossible, an error occurs immediately, halting the program. Let's gracefully defend against this using try-catch.

public class ExceptionExam {
public static void main(String[] args) {
System.out.println("Program starts...");

int num = 100;
int result = 0;

try {
// Error occurs on this line from attempting to divide by 0!
result = num / 0;
// Code after the error won't execute; flow jumps straight to catch block
System.out.println("Result: " + result);

} catch (ArithmeticException e) {
// Because the error is of type ArithmeticException, this block executes.
System.out.println("Exception occurred! You cannot divide by zero mathematically.");
System.out.println("Error message: " + e.getMessage());
}

// Successfully reaching this point means the catch block prevented an abnormal termination.
System.out.println("Program terminates normally.");
}
}

2. Handling Multiple Exceptions at Once (Multi-catch)

As program code grows, multiple types of exceptions might occur simultaneously within a try block—not just dividing by zero, but exceeding an array's bounds or failing to find a file.

In these situations, you can line up multiple catch blocks.

try {
int[] arr = new int[3];
arr[4] = 10; // 1. Array exception occurs here! ArrayIndexOutOfBoundsException
int c = 10 / 0; // This code is unreachable because the exception blew up above
} catch (ArithmeticException e) {
System.out.println("Divided by zero error");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Array out of bounds error");
} catch (Exception e) {
// Since Exception is the supreme parent of all exceptions, it acts as the "catch-all" handler (must be placed last)
System.out.println("An unknown, unexpected error occurred.");
e.printStackTrace();
}

Warning ⚠️: Multiple catch blocks are evaluated in order from top to bottom (like if-else if). Therefore, more generic (parent) exception classes must be placed at the bottom. (If the ancestor of all exceptions, Exception, guards the very top, the catch blocks below it will never get a chance to execute, resulting in a compiler error!)

3. The finally Block - Guaranteed Insurance Code

What if you have cleanup code that absolutely must execute 100% of the time at the very end, regardless of whether an exception occurred or the code ran normally? A classic example is closing an opened database connection or releasing a heavy file object.

For this, Java provides the finally block.

try {
// Code that might throw an exception
System.out.println("Opening database.");

} catch (Exception e) {
// Executes only when an exception occurs
System.out.println("Error occurred!");

} finally {
// Always executes unconditionally, regardless of exceptions! It even executes if there's a return statement in try or catch.
System.out.println("Safely closing the database connection.");
}

The try-catch-finally construct is a vital defensive logic pattern you will encounter frequently in real-world Java applications and frameworks, so be sure to master it.

In the next chapter, we will learn about Custom Exceptions, where we create our very own triggered errors suited for specific business logic domain rules.

Advertisement