Start Learning
Javaneer
Back to stage
Stage 3·Intermediate Java

Exception Handling

Checked vs unchecked, try/catch/finally, try-with-resources, and custom exceptions.

18 min readIntermediate
On this page

Things go wrong: files vanish, networks drop, users type nonsense. Exceptions are Java's structured way to signal and handle these problems without your whole program crashing. Handled well, they make software robust; handled poorly, they hide bugs.

What is an exception?

An exception is an object that represents something going wrong. When a problem occurs, Java throws an exception; if nothing catches it, the program stops and prints a stack trace.

Exceptions are like a smoke alarm

A smoke alarm doesn't put out the fire - it signals a problem loudly so someone can respond. An exception is that alarm: it interrupts normal flow and hands control to code that knows how to deal with the situation. Ignore the alarm, and the building (program) evacuates (crashes).

try / catch / finally

Wrap risky code in a try block; handle failures in catch; run cleanup in finally (which always runs, success or failure):

try {
    int result = 10 / divisor;         // might throw ArithmeticException
    System.out.println(result);
} catch (ArithmeticException e) {
    System.out.println("Can't divide by zero!");
} finally {
    System.out.println("This always runs.");
}

You can catch multiple types, most specific first:

try {
    riskyOperation();
} catch (FileNotFoundException e) {
    // handle a missing file specifically
} catch (IOException e) {
    // handle any other I/O problem
}

Checked vs. unchecked exceptions

Java has two families, and the difference matters:

CheckedUnchecked (Runtime)
ExamplesIOException, SQLExceptionNullPointerException, IllegalArgumentException
WhenExpected, recoverable problemsProgramming bugs
CompilerForces you to handle or declareOptional
Checked = 'bring an umbrella'

A checked exception is a forecast of rain: the compiler insists you prepare for it (handle or declare it). An unchecked exception is tripping over your own shoelaces - a bug you should just fix, so the compiler doesn't nag. Checked means "this can reasonably fail even in correct code."

A method declares checked exceptions it might throw with throws:

void readConfig() throws IOException {
    Files.readString(Path.of("config.txt"));  // may throw IOException
}

try-with-resources: automatic cleanup

Resources like files and database connections must be closed. try-with- resources closes them automatically, even if an exception occurs:

try (var reader = Files.newBufferedReader(Path.of("data.txt"))) {
    System.out.println(reader.readLine());
}   // reader is closed automatically here - no finally needed

Always prefer try-with-resources

Manually closing resources in finally is verbose and easy to get wrong (what if close() also throws?). Any resource implementing AutoCloseable works with try-with-resources - use it for files, streams, sockets, and connections.

Custom exceptions

Create your own exception types for your domain by extending Exception (checked) or RuntimeException (unchecked):

class InsufficientFundsException extends RuntimeException {
    InsufficientFundsException(String message) {
        super(message);
    }
}

void withdraw(double amount) {
    if (amount > balance) {
        throw new InsufficientFundsException("Balance too low");
    }
    balance -= amount;
}

Best practices

  • Catch specific exceptions, not a blanket catch (Exception e).
  • Never swallow silently - an empty catch block hides bugs. At minimum, log.
  • Don't use exceptions for normal flow - they're for exceptional situations.
  • Include context in messages: what failed and why.
  • Fail fast - validate inputs early with IllegalArgumentException.

The worst catch block

An empty catch (Exception e) {} is a bug-hiding trap: it silences problems so they resurface later as baffling behavior. If you truly can't handle it, let it propagate - don't bury it.

Quick check

What is the key difference between checked and unchecked exceptions?

Key takeaways

  • An exception is an object signaling a problem; unhandled, it stops the program.
  • Use try to wrap risky code, catch to handle failures, and finally for cleanup that always runs.
  • Checked exceptions (compiler-enforced) model recoverable problems; unchecked model bugs.
  • try-with-resources auto-closes AutoCloseable resources - prefer it over manual finally.
  • Create custom exceptions for your domain; catch specifically, never swallow silently, and fail fast.

Next, we'll master the Collections Framework - the resizable lists, sets, and maps you'll reach for in nearly every program.