Skip to content
Educora
Advanced17 min10 / 18

Exceptions: handling errors

Catch errors with try/catch/finally, tell checked and unchecked exceptions apart, throw exceptions and create your own exception class.

Check yourself
In this lesson you will learn
  • Explain what an exception is and read a stack trace
  • Use try, catch and finally blocks
  • Tell checked from unchecked exceptions and write a custom exception class

The user typed “abc” instead of their age, a file was deleted, the internet went down — in real programs, not everything goes to plan. A good program does not “crash” in such situations; it reports the problem politely and keeps working. In Java, unexpected situations are handled with exceptions.

What is an exception?

An exception is an object that describes an event which breaks the normal flow of a program. When one happens, Java “throws” it: the current method stops at once, and the exception travels up the chain of calls until some code catches it. If nobody does, the program stops and prints a stack trace to the console.

Java
public class Main {
    public static void main(String[] args) {
        int[] marks = {5, 4, 3};
        System.out.println("Start");
        System.out.println(marks[5]);
        System.out.println("End");
    }
}
Expected output
Start
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 3
	at Main.main(Main.java:5)

Read the stack trace from the top: first the exception's type (ArrayIndexOutOfBoundsException), then its message (index 5 is out of bounds for length 3), then where it happened — line 5 of Main.java. “End” was never printed: after an exception, the rest of the method does not run.

try, catch and finally

We put risky code in a try block. If an exception occurs, control jumps to the catch block of the matching type. The finally block runs in every case — whether an exception happened or not; it is usually used for clean-up work such as closing a file or a connection.

Java
public class Main {
    public static void main(String[] args) {
        String[] inputs = {"42", "abc", "0"};
        for (String input : inputs) {
            try {
                int n = Integer.parseInt(input);
                System.out.println("100 / " + n + " = " + (100 / n));
            } catch (NumberFormatException e) {
                System.out.println("Not a number: " + e.getMessage());
            } catch (ArithmeticException e) {
                System.out.println("Math error: " + e.getMessage());
            } finally {
                System.out.println("-- checked \"" + input + "\"");
            }
        }
    }
}
Expected output
100 / 42 = 2
-- checked "42"
Not a number: For input string: "abc"
-- checked "abc"
Math error: / by zero
-- checked "0"
  • Integer.parseInt("abc") cannot turn the text into a number and throws a NumberFormatException.
  • Dividing an integer by zero causes an ArithmeticException. (Interestingly, 100.0 / 0 throws nothing and gives Infinity.)
  • e.getMessage() returns the exception's message. The program did not stop after an exception — the loop went on with the next value.
  • finally ran in all three cases.

Checked and unchecked exceptions

The common parent of all exceptions is Throwable. From it come Error (serious JVM problems such as running out of memory — usually not caught) and Exception. Exception has a special branch — RuntimeException. This split defines a rule that is unique to Java:

FeatureCheckedUnchecked
Inherits fromException (but not RuntimeException)RuntimeException
Does the compiler insist?yes: catch it or declare it with throwsno
Usually meansa problem outside the program's controla programming mistake
ExamplesIOException, FileNotFoundExceptionNullPointerException, ArithmeticException, IllegalArgumentException

For example, if you write new FileReader("data.txt") without wrapping it in try, the code will not compile: unreported exception FileNotFoundException; must be caught or declared to be thrown. The compiler is saying: “The file might not exist — decide in advance what to do then.”

throw, throws and your own exceptions

You can throw an exception yourself: throw new IllegalArgumentException("..."). This is the best way to stop a method from accepting bad data. To create your own exception class, extend Exception (checked) or RuntimeException (unchecked). A method that throws a checked exception must declare it in its header with throws.

Java
public class Main {
    static void setAge(int age) {
        if (age < 0 || age > 150) {
            throw new IllegalArgumentException("Invalid age: " + age);
        }
        System.out.println("Age set to " + age);
    }

    public static void main(String[] args) {
        try {
            setAge(25);
            setAge(-3);
            setAge(40);
        } catch (IllegalArgumentException e) {
            System.out.println("Error: " + e.getMessage());
        }
        System.out.println("Program continues");
    }
}
Expected output
Age set to 25
Error: Invalid age: -3
Program continues

setAge(40) was never called: as soon as setAge(-3) threw an exception, the try block stopped and control moved to catch. Now let's create our own checked exception — for when a wallet does not have enough money:

Java
public class Main {
    public static void main(String[] args) {
        Wallet wallet = new Wallet(30);
        try {
            wallet.pay(12);
            wallet.pay(25);
        } catch (InsufficientFundsException e) {
            System.out.println(e.getMessage());
            System.out.println("Missing: " + e.getMissing() + " AZN");
        }
    }
}

class InsufficientFundsException extends Exception {
    private final double missing;

    InsufficientFundsException(double missing) {
        super("Not enough money in the wallet");
        this.missing = missing;
    }

    double getMissing() { return missing; }
}

class Wallet {
    private double balance;

    Wallet(double balance) { this.balance = balance; }

    void pay(double amount) throws InsufficientFundsException {
        if (amount > balance) {
            throw new InsufficientFundsException(amount - balance);
        }
        balance -= amount;
        System.out.println("Paid " + amount + ", left " + balance);
    }
}
Expected output
Paid 12.0, left 18.0
Not enough money in the wallet
Missing: 7.0 AZN

Key points

  • An exception is an event that breaks the normal flow; if it is not caught, the program stops and prints a stack trace.
  • try holds risky code, catch catches a specific exception type, and finally always runs.
  • Checked exceptions (IOException) must be caught or declared with throws; RuntimeException subclasses are unchecked.
  • throw new ... throws an exception; for your own exception, extend Exception or RuntimeException.
  • Never write an empty catch block — the information about the error is lost.

Check yourself

10 questions. Every correct answer earns XP.

1 / 10
When does the finally block run?