Checked vs Unchecked Exceptions in Java
Every Java exception is either checked or unchecked. The distinction is enforced by the compiler: checked exceptions must be either catched or declared in a throws clause; unchecked exceptions can be thrown freely.
The hierarchy
Throwable
βββ Error β unchecked (don't catch)
βββ Exception β CHECKED
β βββ IOException β checked
β βββ SQLException β checked
β βββ RuntimeException β UNCHECKED
β βββ NullPointerException
β βββ IllegalArgumentException
β βββ ClassCastException
Checked β the caller must acknowledge
public String read(Path p) throws IOException { // declared
return Files.readString(p);
}
// Caller is forced to choose:
try { read(p); }
catch (IOException e) { log.error("...", e); }
// OR declare it upwards:
public void handle() throws IOException { read(p); }
Unchecked β can be thrown anywhere
public void setAge(int age) {
if (age < 0) throw new IllegalArgumentException("age < 0");
this.age = age;
}
Which to use
| Situation | Pick |
|---|---|
| I/O, network, DB errors the caller might recover from | Checked (IOException, custom) |
| Programming bug (null, bad argument, bad state) | Unchecked (RuntimeException, IllegalArgumentException) |
| Business errors in an application (order not found) | Unchecked (trend toward) |
| JVM problems (OOM, StackOverflow) | Error β don't catch |
The checked-exception debate
Modern Java tends toward unchecked exceptions:
- Spring, Hibernate, Lombok wrap checked exceptions as unchecked.
- Lambdas (
stream().map(...)) can't throw checked exceptions β they force you to wrap. - Kotlin has no checked exceptions at all.
Wrapping checked β unchecked in lambdas
// β Doesn't compile β readString throws IOException
paths.stream().map(Files::readString).toList();
// β
Wrap
paths.stream().map(p -> {
try { return Files.readString(p); }
catch (IOException e) { throw new UncheckedIOException(e); }
}).toList();
Common mistakes
- Declaring
throws Exceptionβ leaks the abstraction; callers catch everything. Be specific. - Converting unchecked to checked β bugs aren't recoverable. Let them propagate.
- Swallowing checked exceptions with an empty catch β the compiler's whole point is defeated.
Related
Pillar: Java exceptions. Siblings: throw, throws, Custom exceptions.