All topics
exceptions
beginner

Checked vs Unchecked Exceptions

Choose between forcing callers to handle a failure (checked) and letting them propagate it (unchecked).

Java's exception hierarchy splits into two families with very different compiler treatment. Checked exceptions (subclasses of Exception but not RuntimeException) must be either caught or declared in the method's throws clause — the compiler enforces it. Unchecked exceptions (RuntimeException and its subclasses, plus Error) carry no such obligation and can propagate freely. Choosing which to throw is a design decision about whether a caller can reasonably be expected to recover.

Checked exception = a contract clause you must initial. Unchecked = a warning sign — you ignore it at your own risk.

Key Concepts

1
The intended distinction is recoverability. Checked exceptions model expected, recoverable conditions outside the program's control — a file that isn't there, a network connection that drops, an I/O failure — where a well-written caller has a sensible response, like retrying or reporting to the user. Unchecked exceptions model programming errors and contract violations — NullPointerException, IllegalArgumentException, IndexOutOfBoundsException — that generally indicate a bug rather than a runtime condition to handle, so forcing every caller to catch them would only clutter the code. Error (such as OutOfMemoryError) sits apart as a serious problem the application normally should not try to catch at all.
NullPointerExceptionIllegalArgumentExceptionIndexOutOfBoundsExceptionErrorOutOfMemoryError
2
In modern practice the pendulum has swung toward unchecked exceptions, partly because checked exceptions compose poorly with lambdas and streams (which cannot throw checked exceptions from standard functional interfaces) and tend to produce noisy throws signatures or, worse, empty catch blocks that swallow failures. Many teams and frameworks — Spring prominently — wrap checked exceptions in unchecked ones at a boundary. The interview-worthy rules: never swallow an exception silently, throw at the right level of abstraction, and when you catch-and-rethrow, preserve the original cause so the stack trace isn't lost.
throws