Week 4 Day 1 — Throwable, Checked, and Unchecked
Goal
Today I want the exception type tree, so “checked vs unchecked” is a compiler rule I can draw, not a slogan.
Main questions:
- What sits under
Throwable? - What is an
Error? - What is a checked exception?
- What is an unchecked exception?
- Why does this split exist?
1. The type tree
Throwable
├── Error // JVM / environment, usually fatal
│ OutOfMemoryError
│ StackOverflowError
│ NoClassDefFoundError
└── Exception
├── RuntimeException // unchecked
│ NullPointerException
│ IllegalArgumentException
│ IllegalStateException
└── (everything else) // checked
IOException
SQLException
InterruptedException
I throw a Throwable. I almost never throw an Error. Application code throws Exception subtypes.
Memory sentence:
Erroris the JVM in trouble.RuntimeExceptionis unchecked. OtherExceptiontypes are checked.
2. Error
An Error means the process is in a bad place: no memory, stack overflow, a class that cannot load.
I do not catch Error to “recover” in a service method. Catching OutOfMemoryError and continuing is a way to corrupt more state.
Error is unchecked: the compiler does not force throws or catch. That is the same compiler treatment as RuntimeException, with a different meaning.
3. Checked exceptions
A checked exception is an Exception that is not a RuntimeException.
If a method can throw one, every caller must catch it or declare throws. The compiler enforces that.
public String read(Path path) throws IOException {
return Files.readString(path);
}
The idea: I/O, JDBC, and similar calls have failures the caller must notice at compile time. IOException is part of the method’s contract, like the return type.
Cost: every layer above must mention IOException or wrap it. That is why Spring and most domain services translate checked library exceptions into unchecked ones (Day 4).
4. Unchecked exceptions
RuntimeException and its subtypes are unchecked. I can throw them without throws. Callers may catch them. They are not forced to.
Typical uses:
- programming mistakes:
NullPointerException,IndexOutOfBoundsException - bad input:
IllegalArgumentException - object in the wrong state:
IllegalStateException - domain failures I will map at the HTTP boundary:
OrderNotFoundException extends RuntimeException
A REST service that throws OrderNotFoundException does not want every method between the repository and the controller to declare throws. Unchecked keeps the happy path readable. A @ControllerAdvice still handles it.
Memory sentence:
Checked forces a compile-time decision. Unchecked means “this is a failure; handle it at a boundary or let it fail the request.”
5. Why the split exists — and why interviews care
Java’s designers wanted I/O-style failures to be visible. C# and Kotlin did not copy checked exceptions. Many Java teams now treat checked as a library concern and unchecked as an application concern.
Interview judgment, not dogma:
- I do not say “never use checked” or “never use runtime.”
- I use checked when I am writing a library method whose caller has a real recovery choice at compile time.
- I use unchecked for domain and REST failures, then translate at the edge.
- I never swallow either kind.
Spring’s DataAccessException is unchecked on purpose: so service code is not littered with SQLException.
6. Spring connection
- Repository methods in Spring Data do not throw
SQLException. They throwDataAccessException(unchecked). @Transactionalrolls back on unchecked by default, not on checkedException. That trap is Day 5.- Controller advice maps exception types to HTTP status. The type tree is the mapping key.
7. Common traps
Trap 1: “Error and RuntimeException are the same.”
Same compiler treatment (unchecked). Different meaning.
Trap 2: “Checked is always better because the compiler helps.”
If every layer only rethrows, the compiler helped nobody. Translate or declare once at a real boundary.
Trap 3: Catching Throwable in a controller.
That also catches Error. Too wide.
Trap 4: throws Exception on a service method.
That erases the type tree. Callers learn nothing.
Practice Questions and Answers
Question 1
What is a checked exception?
Answer:
An Exception that is not a RuntimeException. The compiler requires callers to catch it or declare throws. IOException and SQLException are the usual examples.
Question 2
Is NullPointerException checked?
Answer:
No. It extends RuntimeException, so it is unchecked. The compiler does not force throws. It still means a programming mistake: I dereferenced null.
Question 3
Should I catch OutOfMemoryError in a @Service?
Answer:
No. An Error means the JVM is not in a state I can reliably recover in business code. Let the process fail, and fix the leak or the heap size.
Question 4
Why does Spring wrap SQLException?
Answer:
SQLException is checked. If it leaked, every service method would declare throws SQLException without being able to recover. Spring translates it to an unchecked DataAccessException hierarchy so the service stays readable and a boundary can still map the failure.
Question 5
Checked vs unchecked — what does a REST service throw?
Answer:
Unchecked domain exceptions (OrderNotFoundException, IllegalArgumentException) and let the web layer map them to HTTP. I do not push IOException through the service API unless I am at a real I/O facade that can retry or fail the operation with a clear contract.
Memory sentences
Erroris the JVM.RuntimeExceptionis unchecked. OtherExceptiontypes are checked.
Checked forces a compile-time decision. Domain and REST code usually throw unchecked.
Do not catch
Error. Do not declarethrows Exception.