Unravel โบ Java concepts โบ Errors and logging
Custom exceptions: checked vs unchecked
A checked exception (extends Exception) must be caught or declared with throws; an unchecked one (extends RuntimeException) need not.
Learn these first
At a glance
A checked exception is a "fragile, handle with care" parcel the carrier must declare at every handover.
- 1class OutOfStockException extends RuntimeException { OutOfStockException(String sku) { super("no stock for " + sku); } } is a complete custom exceptionAdd fields (the sku, the requested amount) so handlers can react without parsing the message.
- 2Checked exceptions (IOException, SQLException, your own extends Exception) force callers to handle or declare themThe compiler enforces that something is done about "expected" failures.
- 3Unchecked exceptions (IllegalArgumentException, NullPointerException, your own runtime exceptions) signal bugs or failures that callers usually cannot fix locally; frameworks catch them at the top
- 4Modern style (Spring, most libraries) uses mostly unchecked exceptions with a clear name, and a central handler that maps them to responses
- Choose by what the caller can do: if a sensible caller can recover (retry, ask the user again), checked is defensible; if not, use unchecked
- Always pass the original exception as the cause (super(message, cause)) so the root problem survives
- The compiler enforces checked exceptions at compile time only; the JVM does not distinguish them
public class Stock { public static class OutOfStockException extends RuntimeException { private final String sku; public OutOfStockException(String sku, Throwable cause) { super("no stock for " + sku, cause); this.sku = sku; } public String sku() { return sku; } } public static class SupplierException extends Exception { public SupplierException(String msg) { super(msg); } } void order(String sku, int n) throws SupplierException { if (n <= 0) throw new IllegalArgumentException("n must be positive"); throw new SupplierException("supplier offline"); }}Read the full explanation (about 2 min)
A checked exception (extends Exception) must be caught or declared with throws; an unchecked one (extends RuntimeException) need not. You define your own to give a failure a precise name and carry useful details.
A mental model
A checked exception is a "fragile, handle with care" parcel the carrier must declare at every handover. An unchecked exception is a fire alarm: it goes off wherever it happens, and the building's emergency procedure deals with it.
How it works
class OutOfStockException extends RuntimeException { OutOfStockException(String sku) { super("no stock for " + sku); } } is a complete custom exception. Add fields (the sku, the requested amount) so handlers can react without parsing the message.
Checked exceptions (IOException, SQLException, your own extends Exception) force callers to handle or declare them. The compiler enforces that something is done about "expected" failures.
Unchecked exceptions (IllegalArgumentException, NullPointerException, your own runtime exceptions) signal bugs or failures that callers usually cannot fix locally; frameworks catch them at the top.
Modern style (Spring, most libraries) uses mostly unchecked exceptions with a clear name, and a central handler that maps them to responses.
Going deeper
Choose by what the caller can do: if a sensible caller can recover (retry, ask the user again), checked is defensible; if not, use unchecked. Do not declare throws Exception on everything, which defeats the checking.
Always pass the original exception as the cause (super(message, cause)) so the root problem survives. Add a serialVersionUID only if you really serialize it.
Do not use exceptions for normal control flow (end of loop, "not found" in a hot path): they are slow compared to a return value, and they hide the real flow.
Overriding methods can only throw the same or narrower checked exceptions than the parent method; that is why checked exceptions leak awkwardly through interfaces and lambdas.
Under the hood
The compiler enforces checked exceptions at compile time only; the JVM does not distinguish them. The cost of an exception is mostly filling in the stack trace (fillInStackTrace); exceptions that never need one can override it for speed.
Common mistakes
- Making every custom exception checked.
- Throwing
new Exception("error")with no cause or detail. - Catching
Exceptionand throwing away the stack trace. - Forgetting to pass the cause.
How Unravel recognises it
When you paste code, Unravel looks for these signs of custom exceptions: checked vs unchecked. Spotting them yourself is a good habit when you read unfamiliar code:
- Language constructs:
throws
Part of a learning path
- Errors, logging and tests in depth ยท previous: The exceptions you meet every day ยท next: Exception causes and stack traces
Related concepts
Frequently asked questions
What is Custom exceptions: checked vs unchecked?
A checked exception (extends Exception) must be caught or declared with throws; an unchecked one (extends RuntimeException) need not. You define your own to give a failure a precise name and carry useful details.
What are the most common mistakes with Custom exceptions: checked vs unchecked?
Making every custom exception checked. Throwing new Exception("error") with no cause or detail. Catching Exception and throwing away the stack trace. Forgetting to pass the cause.
How can I see Custom exceptions: checked vs unchecked in real code?
Paste your own Java into Unravel and it will point out where custom exceptions: checked vs unchecked appears, explain how it works at the detail level you choose, and draw the flow of the code around it.