Checked vs Unchecked Exceptions in Java, Explained
Checked exceptions must be handled or declared at compile time; unchecked exceptions happen at runtime and don't have to be declared. Here's the difference, the exception hierarchy, and when to use each.
In Java, checked exceptions are verified at compile time — the compiler forces you to handle or declare them — while unchecked exceptions happen at runtime and carry no such requirement. Checked exceptions model recoverable problems (a missing file); unchecked ones usually signal programming bugs (a null reference). Knowing the difference is a Phase 4 skill from the Java roadmap and a common interview question.
The exception hierarchy
Everything throwable descends from Throwable, which branches:
Throwable
├─ Error (serious JVM problems — don't catch, e.g. OutOfMemoryError)
└─ Exception
├─ RuntimeException → UNCHECKED (e.g. NullPointerException)
└─ (everything else) → CHECKED (e.g. IOException)
So the rule is precise: RuntimeException and its subclasses (plus Error) are unchecked; all other Exceptions are checked.
Checked exceptions
The compiler forces you to deal with these — either catch them or declare them with throws:
void readFile(String path) throws IOException { // declared
Files.readAllLines(Path.of(path)); // can throw IOException
}
// or handle it:
try {
Files.readAllLines(Path.of(path));
} catch (IOException e) {
// recover
}
They represent recoverable, anticipated conditions outside your control — file not found, network failure, a database hiccup. The compiler makes you acknowledge them.
Unchecked exceptions
RuntimeException and its subclasses (NullPointerException, IllegalArgumentException, IndexOutOfBoundsException) need no declaration and aren’t enforced by the compiler:
int[] a = new int[3];
int x = a[5]; // ArrayIndexOutOfBoundsException at runtime
String s = null;
s.length(); // NullPointerException at runtime
These usually mean a programming bug — something that shouldn’t happen if the code is correct. You fix the code rather than routinely catch them.
try / catch / finally
The handling mechanism for both:
try {
risky();
} catch (SpecificException e) {
// handle this specific case
} finally {
// always runs — clean up resources
}
For resources (files, connections), prefer try-with-resources, which closes them automatically:
try (var reader = Files.newBufferedReader(path)) {
// reader auto-closed, even on exception
}
RuntimeException: under it is unchecked, everything else under Exception is checked.
When to use which
- Throw a checked exception for a recoverable condition a caller should anticipate and handle (a failed external operation).
- Throw an unchecked exception for programming errors — invalid arguments, illegal states — that signal a bug to fix, not a condition to routinely catch (
throw new IllegalArgumentException("age must be positive")).
Modern Java codebases often lean toward unchecked exceptions to avoid throws clutter, but checked exceptions remain valuable for genuinely recoverable errors.
throw vs throws
Two similar words, different jobs:
throwraises an exception:throw new IllegalStateException();throwsdeclares, in a method signature, which checked exceptions it may raise:void read() throws IOException.
Common mistakes
- Swallowing exceptions — an empty
catch {}hides bugs. At least log it. - Catching
ExceptionorThrowablebroadly — you’ll catch programming bugs you meant to surface. - Catching
Error—OutOfMemoryErrorand friends shouldn’t be caught; the JVM is in trouble. - Not using try-with-resources — manual
finallycleanup is error-prone; let the language close resources.
Where this fits
Exceptions are Phase 4 of the Java roadmap, part of writing robust object-oriented code, and they pair with the equals/hashCode contract as the “correctness” fundamentals.
Exception design, custom exceptions, and try-with-resources are covered in Java in One Month and the job-ready Java in Three Months; exception strategy at scale is in Java for Staff Engineers.
Checked for recoverable and external, unchecked for bugs — that distinction guides every exception decision.
Frequently asked questions
What is the difference between checked and unchecked exceptions in Java?
Checked exceptions are checked at compile time — the compiler forces you to handle them with try/catch or declare them with throws. They represent recoverable conditions like a missing file (IOException). Unchecked exceptions (RuntimeExceptions) occur at runtime, usually from programming bugs like null access, and do not have to be declared or caught.
What is the Java exception hierarchy?
All exceptions descend from Throwable, which splits into Error (serious problems like OutOfMemoryError you shouldn't catch) and Exception. Exception splits into RuntimeException and its subclasses (unchecked) and all other exceptions (checked). So checked = Exception but not RuntimeException; unchecked = RuntimeException and Error.
When should I use a checked vs unchecked exception?
Use a checked exception for recoverable conditions a caller should anticipate and handle, like network or file errors. Use an unchecked (runtime) exception for programming errors that shouldn't happen if the code is correct, like invalid arguments or null. Many modern Java codebases lean toward unchecked exceptions to avoid clutter.
What is the difference between throw and throws in Java?
throw actually raises an exception: throw new IllegalArgumentException(). throws is part of a method signature declaring which checked exceptions the method might raise, so callers know to handle them: void read() throws IOException. One raises; the other declares.