JavaChecked vs Unchecked Exceptions

Checked vs Unchecked Exceptions

Java splits exceptions into two enforcement categories: checked exceptions, which the compiler forces you to deal with, and unchecked exceptions, which it does not. Understanding which category an exception falls into tells you exactly what the compiler will and will not let you get away with.

Checked Exceptions
A checked exception is any class that extends Exception but does not extend RuntimeException — common examples include IOException and SQLException. If a method can throw one, it must either catch it or declare it with throws in its signature. Skipping both is a compile error.

This does NOT compile

Java
import java.io.FileReader;
import java.io.IOException;

public class UncaughtCheckedDemo {
    public static void main(String[] args) {
        FileReader reader = new FileReader("data.txt"); // compile error!
    }
}
Warning
Compile error: unreported exception FileNotFoundException; must be caught or declared to be thrown. The FileReader constructor declares that it can throw a checked IOException, so every caller must handle that possibility — this is a distinctly Java feature that many other popular languages, including Python, C#, and JavaScript, do not have at all.

Fixed: catch it, or declare it

Java
import java.io.FileReader;
import java.io.IOException;

public class CaughtCheckedDemo {
    public static void main(String[] args) {
        try {
            FileReader reader = new FileReader("data.txt");
        } catch (IOException e) {
            System.out.println("Could not open file: " + e.getMessage());
        }
    }
}
Unchecked Exceptions
An unchecked exception is any RuntimeException subclass (like NullPointerException or IllegalArgumentException), plus Error and its subclasses. The compiler never requires you to catch or declare these — they typically represent programming mistakes rather than conditions you plan for at every call site.

Compiles fine — no catch or throws required

Java
public class UncheckedDemo {
    public static void main(String[] args) {
        int[] numbers = {1, 2, 3};
        System.out.println(numbers[10]); // compiles fine, fails at runtime
    }
}
Side-by-Side Comparison

Aspect

Checked

Unchecked

Base classes

Exception (excluding RuntimeException)

RuntimeException and Error

Compiler enforcement

Must catch or declare with throws

No enforcement at all

Typical meaning

An anticipated, recoverable condition

A programming bug or invariant violation

Examples

IOException, SQLException

NullPointerException, IllegalArgumentException, ArithmeticException

The Ongoing Debate
Note
Checked exceptions were a deliberate design choice meant to force developers to consider failure modes explicitly. In practice, many developers found that they encourage boilerplate — catch blocks that just wrap and rethrow, or worse, swallow the exception silently just to satisfy the compiler. Most languages designed after Java (Kotlin, C#, Scala) chose not to include checked exceptions at all. Neither side of this debate is universally "right" — it is a genuine, still-discussed trade-off between compile-time safety and ergonomic flexibility, and it is worth knowing both perspectives exist rather than treating checked exceptions as an obvious best practice or an obvious mistake.
Tip
A widely used rule of thumb: reach for a checked exception when the caller has a real, expected way to recover (like retrying a failed network call), and use an unchecked exception when the failure represents a bug that no reasonable caller could be expected to recover from at the call site.