Every way to handle a failure
Catch, declare, wrap, clean up, or let it propagate: the exception tools and the strategy that picks between them.
Ask whether this method can do something useful about the failure.
- It can recover (retry, use a default, ask again) →
catchthe specific exception right here. - It can't, and the failure is checked → declare it with
throws, or wrap it in an exception that fits this layer, passing the original as the cause. - Something must be closed whatever happens (a file, a connection) →
try-with-resources, not afinallyyou write yourself. - It's a bug (null, a bad index) → don't catch it; fix the code. Let one top-level handler log it.
- The program ended with a trace → read it from the top for the type and message, then down to the first line in your own code.
The mechanics
Section
What an exception is
Throwing interrupts the method and unwinds the stack.
Section
try, catch, finally
Which clause runs, and where execution resumes.
Runs whether or not an exception was thrown, even after a return.
Formal. Every exception is a Throwable. Error and
RuntimeException, with all their subclasses, are unchecked. Every other
Throwable (for example IOException and InterruptedException) is
checked: if a statement can throw a checked exception, its method must
either catch it or declare it with a throws clause. The compiler checks
this one method at a time, from method headers.
In plain English. Some failures, like a missing file, are a normal
part of the world, and Java makes you write down a plan for them: handle
it here, or warn your callers in the method's header. Programming
mistakes, like a null where an object should be, aren't checked; the
fix is to correct the code.
Example. Files.readAllLines(path) is declared throws IOException,
so calling it without a try/catch or a throws IOException on the
enclosing method fails to compile with unreported exception IOException; must be caught or declared to be thrown. Integer.parseInt("x") throws
the unchecked NumberFormatException, and needs neither.
Why this rule exists. It makes the recoverable failures a method can cause part of its signature, so callers can't forget them.
The compiler's catch-or-declare rule.
Must be caught or declared, for failures a correct program can't rule out.
A RuntimeException or Error; usually a bug to fix.
Passing it on
Section
throw, throws and propagation
How an exception travels up the call stack.
Example
throw new StorageException("save failed", e);Wrapping keeps the original as the cause.
Section
Custom exceptions and wrapping
An exception type for your layer, with the cause attached.
Cleaning up and deciding
Closes every resource, in reverse order, even when the block throws.
Section
A handling strategy
Where to catch, what to log, and the habits that hide failures.
Section
Debugging from a stack trace
From the header to the first frame in your own code.