Chapter 42 of 57

Exception Handling in Java

While running a program, things don't always go exactly as expected. A user might enter the wrong type of input, a file might not exist, or the program might try to divide a number by zero.

When something goes wrong during program execution, Java can generate an exception.

For example:

int result = 10 / 0;

This causes an exception because dividing an integer by zero is not allowed.

If we don't handle the exception, the program can stop unexpectedly.

Exception handling allows us to deal with these problems gracefully instead of letting the program crash.

What is an Exception?

An exception is an event that occurs during program execution that disrupts the normal flow of the program.

For example:

int[] numbers = {10, 20, 30};

System.out.println(numbers[5]);

There is no element at index 5, so Java throws an ArrayIndexOutOfBoundsException.

Another common example is:

int number = Integer.parseInt("hello");

Java cannot convert "hello" into an integer, so it throws a NumberFormatException.

These situations are called exceptions.

The try and catch Blocks

The most basic way to handle an exception is using try and catch.

try {
    int result = 10 / 0;
} catch (ArithmeticException e) {
    System.out.println("Cannot divide by zero.");
}

Output:

Cannot divide by zero.

The code that might cause an exception goes inside the try block.

If an exception occurs, Java moves to the matching catch block.

So you can think of it like this:

try
 ↓
Run risky code
 ↓
Exception?
 ↓ Yes
catch
 ↓
Handle the problem

Why Do We Need try-catch?

Without exception handling:

int result = 10 / 0;

System.out.println("Program continues...");

The program will throw an exception before reaching the second statement.

With try-catch:

try {
    int result = 10 / 0;
} catch (ArithmeticException e) {
    System.out.println("Something went wrong.");
}

System.out.println("Program continues...");

Output:

Something went wrong.
Program continues...

The exception was handled, so the program can continue running.

The catch Block

The catch block specifies which type of exception we want to handle.

For example:

try {
    int result = 10 / 0;
} catch (ArithmeticException e) {
    System.out.println("Division by zero is not allowed.");
}

Here, ArithmeticException is the type of exception we're catching.

The variable e contains information about the exception.

We can also print the exception:

catch (ArithmeticException e) {
    System.out.println(e.getMessage());
}

For example, Java may print a message such as:

/ by zero

Multiple catch Blocks

A try block can potentially cause different types of exceptions. We can use multiple catch blocks to handle them separately.

try {
    int[] numbers = {10, 20, 30};

    System.out.println(numbers[5]);

} catch (ArrayIndexOutOfBoundsException e) {
    System.out.println("Invalid array index.");

} catch (Exception e) {
    System.out.println("Something went wrong.");
}

Java checks the catch blocks and uses the first matching one.

A general Exception catch is usually placed after more specific exception types.

The finally Block

Java also provides the finally block.

The code inside finally generally executes whether an exception occurs or not.

try {
    int result = 10 / 2;
    System.out.println(result);

} catch (ArithmeticException e) {
    System.out.println("Cannot divide by zero.");

} finally {
    System.out.println("This block is executed.");
}

Output:

5
This block is executed.

Even if an exception occurs, the finally block is normally executed.

It's commonly useful for cleanup operations, such as closing resources.

Example with an Exception

Let's look at a simple example:

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

        try {
            int result = 10 / 0;
            System.out.println(result);

        } catch (ArithmeticException e) {
            System.out.println("You cannot divide by zero.");
        }

        System.out.println("Program continues...");
    }
}

Output:

You cannot divide by zero.
Program continues...

Instead of the program stopping with an unhandled exception, we handle the problem and continue.

throw Keyword

Sometimes we want to manually create an exception when a specific condition occurs.

For this, Java provides the throw keyword.

For example:

static void checkAge(int age) {

    if (age < 18) {
        throw new IllegalArgumentException("Age must be at least 18.");
    }

    System.out.println("Access allowed.");
}

Now:

checkAge(15);

will throw an exception with our custom message.

We can handle it:

try {
    checkAge(15);
} catch (IllegalArgumentException e) {
    System.out.println(e.getMessage());
}

Output:

Age must be at least 18.

throw is useful when we want to tell Java that something is invalid according to our program's rules.

throws Keyword

The throws keyword is different from throw.

We use throws in a method declaration to indicate that a method may throw certain exceptions.

For example:

static void readFile() throws Exception {
    // Code that may cause an exception
}

It doesn't actually throw the exception by itself. It tells the code calling the method that the method may produce that exception.

For now, the easiest way to remember the difference is:

throw → actually throws an exception

throws → declares that a method may throw an exception

Checked and Unchecked Exceptions

Java exceptions are commonly divided into two important categories.

Checked exceptions are checked by the compiler. For example, file-related operations can require you to handle or declare certain exceptions.

Unchecked exceptions occur during runtime and generally extend RuntimeException.

Common unchecked exceptions include:

ArithmeticException
NullPointerException
ArrayIndexOutOfBoundsException
NumberFormatException

For example:

int number = Integer.parseInt("abc");

can cause a NumberFormatException.

A Real-World Example

Imagine a login system. A user enters a value that should be a number, but instead enters text.

try {
    int age = Integer.parseInt("twenty");

    System.out.println("Age: " + age);

} catch (NumberFormatException e) {
    System.out.println("Please enter a valid number.");
}

Instead of allowing the program to terminate unexpectedly, we can show the user a useful message.

This is one of the main reasons exception handling is important in real applications.

The Main Idea

Exception handling isn't about preventing every possible error. It's about handling problems properly when they occur.

The basic structure you'll use most often is:

try {
    // Code that might cause an exception
} catch (Exception e) {
    // Handle the exception
}

And when needed, we can also use finally, throw, and throws.

The main thing to remember is:

Exception handling allows your Java program to deal with unexpected problems without abruptly stopping its normal flow.