Checked vs unchecked exceptions in Java
8 min readUpdated
Every Java exception is either checked (the compiler makes you handle it) or unchecked (it does not). Knowing which is which, and when to throw each, makes your error handling clearer and is a guaranteed interview question.
The short answer
- Checked exceptions extend
Exception(but notRuntimeException). You must catch them or declare them withthrows. Example:IOException. - Unchecked exceptions extend
RuntimeException. The compiler does not force handling. Example:NullPointerException. - Errors (
OutOfMemoryError,StackOverflowError) are also unchecked and mean the JVM is in trouble; do not catch them.
| Checked | Unchecked | |
|---|---|---|
| Parent class | Exception | RuntimeException |
| Checked by the compiler | Yes: catch or declare | No |
| Usually means | Something outside your control failed (file, network, database) | A bug or a broken rule in the code |
| Examples | IOException, SQLException, InterruptedException | NullPointerException, IllegalArgumentException, ArithmeticException, IndexOutOfBoundsException |
| Typical response | Recover, retry or report clearly | Fix the code, or validate input earlier |
The exception hierarchy
Throwable
├── Error (unchecked, JVM problems: do not catch)
│ ├── OutOfMemoryError
│ └── StackOverflowError
└── Exception (checked)
├── IOException
│ └── FileNotFoundException
├── SQLException
└── RuntimeException (unchecked)
├── NullPointerException
├── IllegalArgumentException
│ └── NumberFormatException
├── ArithmeticException
└── IndexOutOfBoundsExceptionA checked exception must be handled
Remove the try/catch below and the program does not compile: Files.readString declares throws IOException, so the compiler insists that you deal with it.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class CheckedDemo {
static String readConfig(Path path) throws IOException { // pass it on to the caller
return Files.readString(path);
}
public static void main(String[] args) {
try {
System.out.println(readConfig(Path.of("missing-config.txt")));
} catch (IOException e) { // or handle it here
System.out.println("Could not read config: " + e.getClass().getSimpleName());
}
}
}Output
Could not read config: NoSuchFileException
An unchecked exception points to a bug
Unchecked exceptions compile without any handling. Most of them should be prevented, not caught: check for null, validate input, check the index.
public class UncheckedDemo {
static int parseAge(String text) {
int age = Integer.parseInt(text); // may throw NumberFormatException
if (age < 0) {
throw new IllegalArgumentException("age must not be negative: " + age);
}
return age;
}
public static void main(String[] args) {
for (String input : new String[] {"21", "abc", "-4"}) {
try {
System.out.println("ok: " + parseAge(input));
} catch (IllegalArgumentException e) { // also catches NumberFormatException, a subclass
System.out.println(e.getClass().getSimpleName() + ": " + e.getMessage());
}
}
}
}Output
ok: 21 NumberFormatException: For input string: "abc" IllegalArgumentException: age must not be negative: -4
Writing your own exceptions
Most modern applications use unchecked custom exceptions for business rules (InsufficientBalanceException, OrderNotFoundException) and handle them in one place, such as a Spring @RestControllerAdvice. Use a checked one only when callers can really recover and you want the compiler to remind them.
public class CustomException {
static class InsufficientBalanceException extends RuntimeException {
InsufficientBalanceException(double balance, double amount) {
super("Balance " + balance + " is less than " + amount);
}
}
static double withdraw(double balance, double amount) {
if (amount > balance) throw new InsufficientBalanceException(balance, amount);
return balance - amount;
}
public static void main(String[] args) {
System.out.println(withdraw(1000, 400));
try {
withdraw(1000, 1500);
} catch (InsufficientBalanceException e) {
System.out.println(e.getMessage());
}
}
}Output
600.0 Balance 1000.0 is less than 1500.0
Good practices
- Catch the most specific exception you can handle; never catch
Exceptionjust to hide it. - Never leave a
catchblock empty. At least log the exception. - When you wrap an exception, keep the cause:
throw new DataAccessException("...", e);. - Close resources with try-with-resources instead of
finally. - Do not use exceptions for normal control flow such as ending a loop.
- Write messages that say what went wrong and with which value.
Frequently asked questions
Is NullPointerException checked or unchecked?
Unchecked. It extends RuntimeException, so the compiler does not force you to handle it. Prevent it with null checks or Optional.
Is IOException checked or unchecked?
Checked. Methods that throw it must declare throws IOException, and callers must catch it or declare it too.
Should custom exceptions be checked or unchecked?
Usually unchecked in modern applications, handled centrally. Make one checked only when the caller can and should recover from it.
Can we catch an Error?
You can, but you should not. Errors such as OutOfMemoryError mean the JVM may be in a broken state, and there is rarely a safe way to continue.
Learn it step by step
Practise this, step by step
Short lessons with quizzes, practice and interview questions, from your first program to job-ready.