What is a checked exception and when to use it?
Use a checked exception if:
Junior Level
Definition
Checked exception - an exception type that the Java compiler requires you to handle.
Why: Java designers wanted to force developers to explicitly decide how to react to predictable external failures - a file might be missing, the network might drop. Without checked exceptions, these situations are easy to miss. If a method can throw a checked exception, you must:
- Wrap the call in
try-catch - Or add
throwsto the method signature
Examples
// Compiler will force handling of IOException
public String readFile() throws IOException {
return Files.readString(Paths.get("data.txt"));
}
// Must handle
public void safeRead() {
try {
Files.readString(Paths.get("data.txt"));
} catch (IOException e) {
System.err.println("Failed to read: " + e.getMessage());
}
}
When to use
Use a checked exception if:
- Failure is expected - file might be missing, network might drop
- Failure is recoverable - can retry, try another path
- It is critical - cannot simply “forget” about this situation
Common checked exceptions
IOException- I/O problemsSQLException- database errorsClassNotFoundException- class not foundInterruptedException- thread interrupted
Middle Level
What to choose: throws or try-catch?
- throws - when the method cannot decide how to handle. Let the caller decide.
- try-catch - when you can handle it on the spot: log, return a default value, retry.
Compilation mechanism
The javac compiler checks the call graph. If somewhere in the chain a method with a checked exception is called and it is not handled, compilation fails.
Exception Translation
In large projects with multi-layer architecture, propagating checked exceptions breaks layer encapsulation. In smaller projects, it is acceptable to propagate them upward.
public Order createOrder(Order order) {
try {
return orderRepository.save(order);
} catch (SQLException e) {
throw new OrderStorageException("Failed to save order", e);
}
}
OrderStorageException is a runtime exception. Business logic does not depend on JDBC.
Three conditions for using checked exceptions
- Failure is expected - not a code bug, but an external circumstance
- Failure is recoverable - calling code can do something about it
- Critical for business - cannot be ignored
Lambda and checked exceptions
Functional interfaces do not support checked exceptions:
// Will not compile!
list.stream().map(path -> Files.readString(path))
// Why: Function<T,R> interface does not declare throws in its apply() signature.
// So the lambda cannot propagate a checked exception - compiler won't allow it.
// Solution - wrapper
list.stream().map(path -> {
try {
return Files.readString(path);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
})
Senior Level
Under the Hood: Exceptions attribute
In the .class file, information about throws is stored in the method’s Exceptions attribute. JVM does not use it for runtime control - only for the compiler verifier.
Binary Compatibility
Adding a checked exception to a method in an existing library breaks binary compatibility. All clients will stop compiling.
Removing an exception - binary compatible, but leaves excess code in clients.
Overriding and LSP
The Liskov Substitution Principle dictates the rules:
- A subclass method can not throw the parent’s exceptions
- Can throw subtypes of the parent’s exceptions
- Cannot throw new checked exceptions
Performance
A checked exception is still a Throwable with expensive fillInStackTrace(). For frequent “expected” situations, it’s better to return Optional<T> or Result objects.
Edge Cases
- InterruptedException - a “good” checked exception. When caught, restore the status:
Thread.currentThread().interrupt() - Generic Throws - Java allows
public <E extends Exception> void doWork() throws E - throws Exception - never write this in a public API
Monitoring
Don’t throw Exception or Throwable. Create your own types for clear error separation in Micrometer/Prometheus.
Interview Cheat Sheet
Must know:
- Checked exception - compiler requires handling (
try-catchorthrows) - Use if failure is expected, recoverable, and critical for business
- Common:
IOException,SQLException,ClassNotFoundException,InterruptedException throws- when the method cannot decide how to handle;try-catch- when you can- Exception Translation - wrapping checked in domain unchecked for architectural layers
- Lambda does not support checked exceptions - needs wrapper in
UncheckedIOException - Adding a checked exception breaks binary compatibility of a library
- When overriding, a subclass method cannot add new checked exceptions (LSP)
Frequent follow-up questions:
- Why don’t checked exceptions work with lambdas? - Functional interfaces (
Function,Predicate) don’t declarethrowsin their signature - What happens when adding a checked exception to a public library API? - All clients will stop compiling - breaks binary compatibility
- How to properly handle InterruptedException? - Catch and restore status:
Thread.currentThread().interrupt() - When is a checked exception better than unchecked? - When the caller can do something about it (retry, choose an alternative path)
Red flags (NOT to say):
- “I write
throws Exceptioneverywhere to avoid thinking” - this breaks the method contract - “Checked exceptions are a JVM problem, not an application one” - no, these are application errors
- “I catch all checked exceptions and do nothing” - silently swallowing errors
Related topics:
- [[What is the difference between checked and unchecked exceptions]]
- [[What is an unchecked exception (Runtime Exception)]]
- [[Which exceptions must be handled]]
- [[What is at the top of the exception hierarchy]]
- [[What is Throwable]]