💥 Exceptions & Errors · Intermediate

Checked vs unchecked in Java

Checked must be handled or declared; unchecked need not be.

🧩 The mysteryCall Thread.sleep(10) in a plain method and your code refuses to compile. Divide by zero and it compiles happily. What's the difference?

The compiler's checklist

Checked exceptions are Exception subclasses outside RuntimeException — IOException, InterruptedException. For these the compiler enforces a rule: handle or declare. Either catch it, or add throws to the method signature.

void load() throws IOException {   // declare
    Files.readString(Path.of("a.txt"));
}
🔮 Predict it

A short nap

Thread.sleep can throw InterruptedException. What happens?

void nap() {
    Thread.sleep(10);
}
void main() {
    nap();
    System.out.println("rested");
}
  1. rested
  2. Compile error
  3. Throws InterruptedException
Show the answer

InterruptedException is checked. nap() neither catches it nor declares throws InterruptedException, so the compiler rejects it.

Unchecked: no paperwork

Unchecked exceptions — RuntimeException, Error and their subclasses — need neither catch nor throws. A method that may throw NullPointerException doesn't have to declare it. The compiler stays quiet, and the problem shows up at runtime.

🔮 Predict it

Compiles fine, then…

No throws clause anywhere. What happens?

void parse() {
    throw new IllegalStateException("bad");
}
void main() {
    parse();
    System.out.println("done");
}
  1. Compile error: parse() must declare throws
  2. Throws IllegalStateException
  3. done
Show the answer

IllegalStateException is unchecked, so it compiles. At runtime it propagates out of main before done is printed.

🤔 Think first

Which kind should you throw?

Your library reads an optional config file. It may legitimately be missing, and callers can recover with defaults. Checked or unchecked?

Think about it, then reveal the answer

Checked, like IOException. Java's philosophy: checked for recoverable problems outside your control (missing files, network), so callers must plan for them; unchecked for bugs (an unexpected null, a bad index).

⚠️ The trap

Lambdas and checked exceptions

Function, Predicate and friends declare no checked exceptions, so a lambda calling Files.readString (which throws IOException) won't compile inside map. Catch inside the lambda, or rethrow as UncheckedIOException.

paths.stream()
     .map(p -> Files.readString(p)) // error
     .toList();
💼 In the real world

A long-running debate

Many frameworks convert checked exceptions into unchecked ones: Spring turns SQLException into its DataAccessException family, so business code isn't buried in throws clauses. Knowing both kinds lets you read such code — and choose deliberately in your own APIs.

Key takeaways

  1. Checked: handle or declare (IOException, InterruptedException)
  2. Unchecked: RuntimeException and Error subclasses
  3. The compiler only enforces checked exceptions
  4. Standard functional interfaces (Function, Predicate) can't throw checked exceptions

💡 A checked exception is a road sign the map makes you acknowledge; an unchecked one is a pothole nobody warned you about.

🤯 Did you know?

C# and Kotlin deliberately left checked exceptions out — Java is one of the very few mainstream languages where the compiler enforces them.

Practice questions

What does this print?

void load() {
    throw new IOException("missing");
}
void main() {
    load();
}
  1. Compile error
  2. Throws IOException
  3. Prints missing
Check your answer

Compile error. IOException is checked. load() neither catches it nor declares throws IOException, so the compiler rejects it.

What does this print?

void parse() {
    throw new IllegalStateException("bad");
}
void main() {
    parse();
    System.out.println("done");
}
  1. Compile error: parse() must declare throws
  2. Throws IllegalStateException
  3. done
  4. bad
Check your answer

Throws IllegalStateException. IllegalStateException is unchecked, so it compiles without throws. At runtime it propagates out of main before "done".

Next: an exception is thrown — but which catch block gets it when there are three in a row?