Java Checked Exception: Syntax and Handling
java checked exception: Learn how Java checked exceptions work, how the compiler enforces handling, and when to use throws versus try-catch in real code.
java checked exception requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.
In Java, a checked exception is an exception that the compiler requires you to handle or declare. When a method can throw a checked exception, the compiler verifies that every caller either catches it or declares it in its own throws clause. This is the key difference from unchecked exceptions, which extend RuntimeException and can propagate without any declaration.
What the Compiler Enforces
The Java compiler treats exceptions that extend Exception (but not RuntimeException) as checked. If a method calls code that can throw a checked exception, the method must either catch the exception in a try-catch block or declare it with throws so callers know about it. This enforcement happens at compile time. The code below will not compile because FileReader's constructor throws FileNotFoundException, which is checked.
import java.io.FileReader; public class FileOpener { public void open(String path) { FileReader reader = new FileReader(path); // compile error } }
The compiler reports that FileNotFoundException must be caught or declared. Adding a throws clause resolves the error:
import java.io.FileReader; import java.io.FileNotFoundException; public class FileOpener { public void open(String path) throws FileNotFoundException { FileReader reader = new FileReader(path); } }
Checked vs Unchecked Exceptions
Java divides exceptions into two categories based on whether the compiler requires handling.
| Category | Base class | Compiler requirement | Typical examples |
|---|---|---|---|
| Checked | Exception | Must be caught or declared | IOException, SQLException, InterruptedException |
| Unchecked | RuntimeException | No declaration required | NullPointerException, IllegalArgumentException, ArithmeticException |
The distinction exists so that failures a caller can reasonably be expected to recover from are visible in the method signature. Unchecked exceptions represent programming errors or conditions that are typically not recoverable at the call site.
Declaring a Checked Exception with throws
The throws clause appears in the method signature after the parameter list. A method can declare multiple checked exceptions separated by commas.
public void readConfig(String path) throws IOException, InterruptedException { // reading a file and sleeping between retries }
Declaring an exception does not prevent it from being thrown. It only informs the compiler and callers that the method may fail in that way. The method body can throw the exception directly or call other methods that throw it.
Handling a Checked Exception with try-catch
When a checked exception is caught, the catch block must reference the exception type or a supertype. The compiler verifies that the catch block can actually catch the exception being thrown.
import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; public class ConfigLoader { public String load(Path path) { try { return Files.readString(path); } catch (IOException e) { return ""; } } }
Returning an empty string on failure is a decision that hides the problem. A better approach is to wrap the exception in an unchecked type when the caller cannot meaningfully recover.
public class ConfigLoader { public String load(Path path) { try { return Files.readString(path); } catch (IOException e) { throw new IllegalStateException("Unable to read config", e); } } }
The original IOException is passed as the cause, so the failure chain remains available during debugging.
Choosing Between throws and try-catch
The decision depends on whether the caller can act on the failure. If the caller can retry, fall back, or inform the user, declare the exception and let the caller decide. If the failure indicates a programming error or a condition the caller cannot handle, catch the exception at the boundary and wrap it in an unchecked exception.
A common pattern is to declare the checked exception on internal service methods and catch it at the application boundary, where the error is converted into a response the user can understand.
When to Design a Custom Checked Exception
A custom checked exception is appropriate when a specific failure condition needs to be part of the method contract. The exception class extends Exception and typically provides constructors that match the standard exception constructors.
public class InsufficientBalanceException extends Exception { public InsufficientBalanceException(String message) { super(message); } }
Methods that can fail with this condition declare it in their signature, and callers are forced to decide how to handle it. This is useful in domain logic where the failure is a normal business outcome rather than a bug.
Common Pitfalls
The most common pitfall is catching a checked exception and doing nothing with it. An empty catch block hides the failure and makes the program harder to debug.
Another pitfall is declaring a broad exception type like Exception in a throws clause. This forces every caller to handle or declare Exception, which removes the useful information about what can actually fail.
A third pitfall is over-declaring. A method that declares exceptions it never throws makes the signature misleading and forces callers to write unnecessary handling code.
Runtime Cost and Maintainability
Checked exceptions have no direct runtime cost beyond the normal exception machinery. The compiler enforcement happens at compile time. However, the design cost is real. A method signature that declares checked exceptions is part of the public contract, and changing it breaks callers. This makes checked exceptions a maintainability concern for libraries and shared code.
When a library method adds a checked exception to its signature, every caller must be updated. This is why many modern Java libraries prefer unchecked exceptions for conditions that are not expected to be handled at every call site. The choice between checked and unchecked is therefore a design decision about the API contract, not a performance decision.