Career OS

Learn · OOP & Java

Exceptions & Error Handling

Things go wrong — a file’s missing, the network drops, a number won’t parse. Exceptions let your program deal with it instead of just dying.

Before we start

📋 What you’ll learn
  • What exceptions are and why they beat crashing
  • try / catch / finally / throw
  • Checked vs unchecked exceptions
  • How to handle errors well (not swallow them)
✅ After this you’ll be able to
  • Wrap risky code and recover gracefully
  • Explain checked vs unchecked
  • Avoid the classic error-handling mistakes

Why you’re learning it: real systems fail constantly; handling failure well is what separates hobby code from production code — and it’s asked in interviews. ⏱️ ~20 min.

The idea — a safety net

An exception is the program saying “something went wrong here” and jumping to your plan B instead of crashing. You wrap risky code in try, handle the problem in catch, and clean up in finally.

try {
    int x = Integer.parseInt(input);   // might fail
} catch (NumberFormatException e) {
    // plan B: tell the user it wasn't a number
} finally {
    // always runs — close files, release locks
}

What actually happens when it’s thrown

The moment the JVM hits something it can’t continue past, it does three things — this is the whole mental model:

An object climbing the stack looking for a catcher — that picture is everything. The rest is just syntax.

The family tree

Everything you can throw descends from one class, Throwable, which splits into two branches that mean very different things:

Throwable
├── Error              ← the JVM itself is dying — you do NOT catch these
│   ├── OutOfMemoryError
│   └── StackOverflowError
└── Exception          ← your program hit a problem — YOUR territory
    ├── IOException           (checked)
    ├── SQLException          (checked)
    └── RuntimeException      (unchecked — the special subtree)
        ├── NullPointerException
        ├── ClassCastException
        └── IllegalArgumentException

Error means the JVM is out of memory or blown its stack — there’s nothing sensible to do, so you let it die. Exception is where you live. And one subtree inside it — RuntimeException — gets special treatment from the compiler.

Checked vs unchecked

✅ Checked

Problems you’re expected to plan for — a missing file, a network error. Java forces you to handle or declare them.

⚠️ Unchecked

Bugs — null pointer, index out of bounds, divide by zero. They mean “fix the code,” not “handle at runtime.”

The dividing line is RuntimeException: anything under it is unchecked; any other Exception is checked. Why does the compiler force you to handle checked ones? Because the outside world will fail no matter how perfect your code is — a file can be deleted between checking it exists and opening it. The compiler is saying: “this failure isn’t optional, decide now what happens.” Unchecked exceptions are programmer mistakes — the fix isn’t a catch, it’s correcting the code so the bug can’t happen.

Handle errors well

try-with-resources — the modern cleanup

The old way of closing a file used finally — and almost everyone got it subtly wrong (null checks, and an exception inside close() masking the real one):

// OLD WAY — don't write this anymore
BufferedReader reader = null;
try {
    reader = Files.newBufferedReader(Path.of("notes.txt"));
    System.out.println(reader.readLine());
} catch (IOException e) {
    System.out.println("Could not read file: " + e.getMessage());
} finally {
    if (reader != null) {
        try { reader.close(); } catch (IOException ignored) {}
    }
}

The modern way — declare the resource in the try parentheses and Java closes it for you automatically, even when an exception flies out:

// The reader is closed automatically — success OR exception
try (BufferedReader reader = Files.newBufferedReader(Path.of("notes.txt"))) {
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }
} catch (IOException e) {
    System.out.println("Could not read notes.txt: " + e.getMessage());
}

Anything that implements AutoCloseable works here — files, database connections, HTTP clients. Multiple resources close in reverse order. finally still exists for non-resource cleanup, but for closing things, try-with-resources won permanently.

Write your own exception

Standard exceptions describe generic failures. Your business logic has specific failures that deserve specific exceptions — with messages that carry context someone can read at 2 AM without opening a debugger:

public class InsufficientBalanceException extends Exception {
    public InsufficientBalanceException(int requestedRupees, int availableRupees) {
        super("Withdrawal of Rs " + requestedRupees + " failed. Balance is Rs "
              + availableRupees + ". Short by Rs " + (requestedRupees - availableRupees));
    }
}

Why extend Exception (checked) and not RuntimeException? Because the caller can realistically recover — show the user “insufficient balance, you need Rs 3000 more.” A short balance is a normal business event, not a bug. Rule of thumb: caller can recover → checked; programmer error → unchecked.

Reading a stack trace — the daily skill

In a real project an exception travels through layers and gets wrapped on the way, so the trace ends up looking like this:

Exception in thread "main" java.lang.RuntimeException: Could not process withdrawal
    at com.bank.WithdrawalService.process(WithdrawalService.java:31)
    at com.bank.Main.main(Main.java:12)
Caused by: InsufficientBalanceException: Withdrawal of Rs 5000 failed. Balance is Rs 2000. Short by Rs 3000
    at com.bank.Account.withdraw(Account.java:18)
    at com.bank.WithdrawalService.process(WithdrawalService.java:28)
    ... 1 more

How to read it — same order, every time:

Where you’ll use it — real life

🌐 API calls

The bank times out — you catch it and retry or mark it, instead of crashing (your EMV world).

🗄️ Database

A failed transaction throws — you catch and roll back.

📥 User input

Bad input shouldn’t take the app down — catch and return a 400.

🧹 Cleanup

finally guarantees connections close even when things fail.

Interview check — say these out loud

🗣️ The 2-minute explain test

Out loud: “What do try/catch/finally do, and what’s the difference between checked and unchecked exceptions?” Log it in your Journal.


Next: Generics →

Saves your progress on this device.
00:00