00:00

Checked vs Unchecked Exceptions in Java – Explained with Examples

Java divides exceptions into two groups based on whether the compiler checks that you handle them. Checked exceptions must be caught or declared, or your code will not compile. Unchecked exceptions can be thrown anywhere without any declaration. This design decision affects how you write methods, how you design APIs, and how you deal with errors in lambdas and streams.

This tutorial explains both groups, shows them in action, compares them side by side, and gives practical guidance on which to use.

1. Which Exceptions Are Checked?

Checked and unchecked exception hierarchy in Java
  • Unchecked: RuntimeException and all its subclasses, plus Error and its subclasses.
  • Checked: every other subclass of Exception (and Throwable itself).

2. Checked Exceptions: Catch or Declare

The compiler enforces the catch-or-declare rule for checked exceptions. Calling a method that throws one without handling it is a compile error:

javac output
Bad.java:2: error: unreported exception IOException; must be caught or declared to be thrown
public class Bad { public static void main(String[] a) { System.out.println(Files.size(Path.of("x"))); } }
                                                                                      ^
1 error

Declaring it with throws and catching it in the caller satisfies the rule:

CheckedDemo.java
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

public class CheckedDemo {
    // Checked: the compiler forces callers to deal with IOException
    static long fileSize(String name) throws IOException {
        return Files.size(Path.of(name));
    }

    public static void main(String[] args) {
        try {
            System.out.println(fileSize("does-not-exist.csv"));
        } catch (IOException e) {
            System.out.println("Handled checked exception: " + e.getClass().getSimpleName());
        }
    }
}
Output
Handled checked exception: NoSuchFileException

3. Unchecked Exceptions: Fix the Cause

Unchecked exceptions compile without any handling. They usually point to a bug or invalid input, so the best response is often to prevent them with a check rather than to catch them:

UncheckedDemo.java
import java.util.List;

public class UncheckedDemo {
    // Unchecked: compiles without try-catch or throws; fails only at runtime
    static String thirdItem(List<String> items) {
        return items.get(2);
    }

    public static void main(String[] args) {
        System.out.println(thirdItem(List.of("a", "b", "c")));

        // Better than catching: prevent the bug with a check
        List<String> shortList = List.of("a");
        if (shortList.size() > 2) {
            System.out.println(thirdItem(shortList));
        } else {
            System.out.println("List too short, no third item");
        }

        try {
            thirdItem(shortList);
        } catch (IndexOutOfBoundsException e) {
            System.out.println("Unchecked exception at runtime: " + e.getMessage());
        }
    }
}
Output
c
List too short, no third item
Unchecked exception at runtime: Index: 2 Size: 1

4. Checked vs Unchecked: Comparison

AspectCheckedUnchecked
ExtendsException (not RuntimeException)RuntimeException (or Error)
Checked by compilerYes: catch or declareNo
throws clauseRequired if not caughtOptional
Typical causeExternal conditions: files, network, database, interruptionProgramming errors or invalid arguments
Can the caller recover?Usually, in some wayUsually by fixing the code
ExamplesIOException, SQLException, InterruptedException, ClassNotFoundExceptionNullPointerException, IllegalArgumentException, ArithmeticException, IndexOutOfBoundsException
Works smoothly in lambdasNoYes

5. Checked Exceptions and Lambdas

Standard functional interfaces such as Function do not declare checked exceptions, so a lambda cannot throw one. The common workaround is to wrap it in an unchecked exception, such as UncheckedIOException, and unwrap it outside:

WrapChecked.java
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.List;

public class WrapChecked {
    static String load(String name) throws IOException {
        if (name.startsWith("x")) throw new IOException("cannot read " + name);
        return name.toUpperCase();
    }

    public static void main(String[] args) {
        List<String> names = List.of("alpha", "beta", "xray");
        try {
            // Lambdas in streams cannot throw checked exceptions: wrap them in an unchecked one
            List<String> loaded = names.stream()
                    .map(n -> {
                        try {
                            return load(n);
                        } catch (IOException e) {
                            throw new UncheckedIOException(e);
                        }
                    })
                    .toList();
            System.out.println(loaded);
        } catch (UncheckedIOException e) {
            System.out.println("Stream failed: " + e.getCause().getMessage());
        }
    }
}
Output
Stream failed: cannot read xray

6. Which Should You Use?

  • Use a checked exception when the caller can reasonably recover and you want the compiler to remind every caller, for example a file that may not exist in a desktop tool.
  • Use an unchecked exception for programming errors (bad arguments, wrong state), and when callers usually cannot do anything except report the error.
  • Many modern frameworks (Spring, Hibernate, most cloud SDKs) prefer unchecked exceptions and handle them centrally, translating checked JDK exceptions where needed.
  • Whatever you choose, document it with Javadoc @throws.

7. The Debate in Brief

Supporters of checked exceptions say they make failure modes explicit and impossible to forget. Critics say they create boilerplate, encourage empty catch blocks, leak implementation details through throws clauses, and clash with lambdas. Java itself keeps them, while newer JVM languages such as Kotlin and Scala treat all exceptions as unchecked.

8. Summary

  • Checked exceptions extend Exception (not RuntimeException) and must be caught or declared.
  • Unchecked exceptions extend RuntimeException or Error and need no handling by rule.
  • Checked exceptions usually represent external, recoverable conditions; unchecked ones usually represent bugs.
  • In lambdas, wrap checked exceptions in unchecked ones such as UncheckedIOException.
  • Choose based on whether callers can reasonably recover.

Related Tutorials