Java does not treat every exception in exactly the same way. Some exceptions are checked by the compiler before your program can run. These are called checked exceptions.
The important idea is that a checked exception represents a condition that Java expects the programmer to acknowledge. If a method can produce a checked exception, the code must either handle it with try-catch or declare it with throws.
Why Checked Exceptions Exist
Consider reading a file from a computer. The file might not exist, permissions might be insufficient, or the underlying storage operation might fail. These are realistic conditions that a well-designed program should consider.
Java's checked-exception mechanism forces developers to make an explicit decision about such failures instead of silently ignoring them.
Remember: A checked exception is checked by the compiler. You must handle it or declare it.
Where Checked Exceptions Fit in the Hierarchy
Checked exceptions are generally exceptions that extend Exception but are not subclasses of RuntimeException.
Throwable
├── Error
└── Exception
├── RuntimeException
│ ├── NullPointerException
│ ├── IllegalArgumentException
│ └── ArithmeticException
│
├── IOException
├── SQLException
└── ClassNotFoundException
The exceptions under Exception that are not under RuntimeException are typically checked exceptions.
The Compiler's Role
The defining characteristic of checked exceptions is compile-time enforcement. If your code calls a method that declares a checked exception, Java requires you to deal with that possibility.
public static void readFile() throws IOException {
FileReader reader = new FileReader("data.txt");
}
Suppose another method calls readFile() without handling or declaring the exception:
public static void process() {
readFile();
}
The compiler reports an error because IOException is checked and the calling method has not taken responsibility for it.
Two Ways to Handle a Checked Exception
Java gives you two primary choices when a checked exception can reach your method.
| Approach | Meaning |
|---|---|
| try-catch | Handle the exception in the current method. |
| throws | Declare the exception and pass responsibility to the caller. |
Handling with try-catch
public static void readFile() {
try {
FileReader reader = new FileReader("data.txt");
System.out.println("File opened.");
} catch (IOException e) {
System.out.println("Unable to open the file.");
}
}
The exception is handled inside the method, so the method does not need to declare IOException with throws.
Handling with throws
public static void readFile()
throws IOException {
FileReader reader = new FileReader("data.txt");
}
Here, the method does not handle the exception. Instead, it tells the caller that an IOException may propagate.
A Complete Example
import java.io.FileReader;
import java.io.IOException;
public class CheckedExceptionDemo {
public static void main(String[] args) {
try {
FileReader reader =
new FileReader("data.txt");
System.out.println("File opened.");
reader.close();
} catch (IOException e) {
System.out.println(
"Could not access the file."
);
}
}
}
Opening and closing the file can involve an IOException. Because it is checked, the compiler requires appropriate handling or declaration.
Common Checked Exception Examples
| Exception | Typical Situation |
|---|---|
| IOException | File, stream, or other input/output operation fails. |
| SQLException | A database operation encounters a failure. |
| ClassNotFoundException | A requested class cannot be located. |
| InterruptedException | A thread is interrupted while waiting or sleeping. |
| FileNotFoundException | A requested file cannot be opened or found. |
Checked Exception Example with a Database
public static void connectToDatabase()
throws SQLException {
// Database connection code
}
A database connection can fail for many external reasons. Declaring SQLException communicates that possibility to the caller.
A higher layer can then decide whether to retry, log the problem, show an error response, or take another appropriate action.
Checked Exceptions and Method Calls
The checked-exception rule becomes especially noticeable when methods call other methods.
public static void methodC()
throws IOException {
// May throw IOException
}
public static void methodB()
throws IOException {
methodC();
}
public static void methodA() {
try {
methodB();
} catch (IOException e) {
System.out.println("Operation failed.");
}
}
The exception is allowed to propagate from methodC() to methodB(). Eventually, methodA() handles it.
This is a good illustration of how exception responsibility can move upward through application layers.
Checked Exceptions in Custom Classes
You can create your own checked exception by extending Exception.
class InvalidOrderException extends Exception {
public InvalidOrderException(String message) {
super(message);
}
}
A method can then declare and throw it:
public static void placeOrder(int quantity)
throws InvalidOrderException {
if (quantity <= 0) {
throw new InvalidOrderException(
"Order quantity must be greater than zero."
);
}
System.out.println("Order placed.");
}
Because the custom exception extends Exception, it becomes a checked exception unless it is placed under the RuntimeException branch.
Checked vs Unchecked Exceptions
| Feature | Checked | Unchecked |
|---|---|---|
| Compiler checks handling | Yes | No |
| Must catch or declare | Yes | No |
| Typical base | Exception excluding RuntimeException | RuntimeException |
| Examples | IOException, SQLException | NullPointerException, IllegalArgumentException |
| Common source | External or recoverable conditions | Programming errors or invalid runtime state |
A Real-World Analogy
Think of checked exceptions like a delivery form that requires a signature. The system will not let the process continue until someone acknowledges the important condition.
Unchecked exceptions are different. Java does not force you to sign for every possible problem. The responsibility remains with the developer to write code that avoids invalid states and handles failures appropriately.
The analogy is not perfect, but it captures the central distinction: checked exceptions create a compile-time obligation.
Do Checked Exceptions Mean the Error Is Recoverable?
Not necessarily. This is an important distinction.
A checked exception indicates that the compiler requires the possibility to be acknowledged. It does not guarantee that the application can successfully recover from the problem.
For example, a database might be unavailable for an extended period. The application may handle the SQLException, but handling does not automatically mean recovery is possible.
Why Some Developers Avoid Checked Exceptions
Checked exceptions can make failure handling explicit, but they can also become cumbersome in large applications. If an exception must be declared across many layers without adding meaningful recovery decisions, method signatures can become noisy.
This is one reason modern Java design often uses checked exceptions selectively rather than treating them as the solution to every failure scenario.
Industry Insight: The question is not simply "Should this exception be checked?" A better design question is "Does forcing callers to acknowledge this failure lead to clearer and more reliable application behavior?"
Common Beginner Mistakes
- Assuming every exception must be caught.
- Confusing checked exceptions with exceptions that are always recoverable.
- Catching a checked exception and doing nothing with it.
- Declaring broad exceptions such as Exception everywhere without considering the actual failure.
- Creating custom checked exceptions without a clear reason for requiring callers to handle them.
- Thinking throws handles the exception instead of merely declaring it.
Best Practices
- Use checked exceptions when callers genuinely need to acknowledge an important failure condition.
- Handle exceptions where the application has enough context to make a meaningful decision.
- Preserve useful exception information when propagating failures.
- Avoid empty catch blocks.
- Use precise exception types instead of unnecessarily broad declarations.
- Consider application architecture before introducing custom checked exceptions.
Interview Insights
A common interview question is: "What makes an exception checked?" The practical answer is that the compiler requires checked exceptions to be either caught or declared. In the exception hierarchy, they generally extend Exception without extending RuntimeException.
Another common question is: "Can we create a custom checked exception?" Yes. Extend Exception directly or through another appropriate checked-exception class.
You may also be asked whether checked exceptions are always better than unchecked exceptions. There is no universal answer. The right choice depends on the failure, the API contract, and whether compile-time enforcement improves the design.
Quick Revision
| Concept | Key Idea |
|---|---|
| Checked exception | An exception whose handling or declaration is enforced by the compiler. |
| Handling | Use try-catch to process the exception locally. |
| Declaration | Use throws to pass responsibility to the caller. |
| Examples | IOException, SQLException, ClassNotFoundException. |
| Custom checked exception | Usually created by extending Exception. |
| Recoverability | Being checked does not guarantee that recovery is possible. |
Checked exceptions are Java's way of making certain failure paths visible during compilation. They can improve reliability when used thoughtfully because callers are forced to acknowledge important operations that may fail. But good exception design is about more than satisfying the compiler; the real goal is to create clear, maintainable failure-handling contracts. The next chapter explores the other major category: unchecked exceptions.
