<code>try</code> / <code>catch</code> / <code>finally</code> in Java

try / catch / finally is Java's mechanism for handling exceptions. The try block holds code that might throw; catch blocks handle specific exception types; finally always runs β€” success, exception, or return.

Basic shape

try {
    doRisky();
} catch (IOException e) {
    log.error("IO failed", e);
} catch (IllegalStateException e) {
    log.warn("bad state", e);
} finally {
    cleanup();                // always runs
}

Multi-catch (Java 7+)

try {
    ...
} catch (IOException | SQLException e) {
    log.error("IO or DB", e);
    throw new ServiceException(e);
}

Catches any of the listed types; e is effectively final inside the block.

Order matters β€” most specific first

// ❌ Won't compile β€” IOException never reached
try { ... }
catch (Exception e)   { ... }
catch (IOException e) { ... }

// βœ…
try { ... }
catch (IOException e) { ... }
catch (Exception e)   { ... }

What finally actually does

finally runs:

  • After normal completion of try.
  • After any catch completes.
  • When the try block returns β€” yes, even then.
  • When an uncaught exception propagates out.

Except if the JVM exits (System.exit, Runtime.halt) or the thread is killed.

The return-in-finally trap

public int f() {
    try      { return 1; }
    finally  { return 2; }   // ❌ swallows the return from try
}
// f() returns 2

Never return from finally. Use it only for cleanup.

Prefer try-with-resources for cleanup

// ❌ easy to forget close, hard to do right
BufferedReader r = null;
try {
    r = Files.newBufferedReader(path);
    ...
} finally {
    if (r != null) r.close();   // what if close() throws?
}

// βœ… Java 7+
try (var r = Files.newBufferedReader(path)) {
    ...
}  // close() called automatically, even on exception

Catching the right level

  • Narrow catches near the source if you can actually recover (retry, fallback).
  • Broad catches at the top (request handler, main thread) to log and return a sensible error.
  • Never empty-catch β€” at minimum log the exception.

Common mistakes

  • Catching Exception or Throwable without logging β€” swallows real bugs.
  • Losing the cause β€” throw new MyException("failed") loses the stack. Use new MyException("failed", e).
  • return in finally β€” subtle and surprising. Never do it.
  • Using exceptions for control flow β€” ~100Γ— slower than an if. Validate up front.

Related

Pillar: Java exceptions. Siblings: try-with-resources, throw, throws clause.