Checked vs Unchecked Errors
Part of the Object Oriented Programming section of Coddy's Java journey — lesson 61 of 87.
You've seen that Java's exception hierarchy splits into different branches. The key distinction you need to understand is between checked and unchecked exceptions—this affects how you must handle them in your code.
Checked exceptions are exceptions that the compiler forces you to handle. They extend Exception directly (not through RuntimeException). You must either catch them or declare them with throws:
// Must handle IOException - it's checked
public void readFile(String path) throws IOException {
FileReader reader = new FileReader(path); // May throw IOException
}
// Or catch it
public void readFileSafe(String path) {
try {
FileReader reader = new FileReader(path);
} catch (IOException e) {
System.out.println("File error: " + e.getMessage());
}
}Unchecked exceptions extend RuntimeException. The compiler doesn't require you to handle them—they typically indicate programming errors like null references or invalid array access:
// No throws declaration needed
public int divide(int a, int b) {
return a / b; // May throw ArithmeticException (unchecked)
}
String name = null;
name.length(); // NullPointerException (unchecked)When creating custom exceptions, choose the parent class based on how you want callers to handle them. Use checked exceptions for recoverable conditions the caller should anticipate. Use unchecked exceptions for programming errors that shouldn't occur in correct code.
Challenge
EasyLet's build an age verification system that demonstrates the key difference between checked and unchecked exceptions! You'll create custom exceptions of both types and see how the compiler treats them differently.
You'll organize your code across four files:
InvalidAgeException.java: Create a checked exception for age validation failures. This exception should extendExceptiondirectly, meaning callers will be forced to handle it. Include a constructor that accepts a message and passes it to the parent class.NegativeAgeException.java: Create an unchecked exception for when someone provides a negative age (a programming error that shouldn't happen with correct input). This should extendRuntimeException. Include a constructor that accepts and passes a message to the parent.AgeVerifier.java: Create a class that validates ages using both exception types. Include two static methods:verifyAge(int age)- This method should throwNegativeAgeException(unchecked) with message"Age cannot be negative: [age]"if the age is less than 0. If the age is less than 18, throwInvalidAgeException(checked) with message"Must be 18 or older: [age]". Otherwise, printAge [age] verified successfully. Since this method throws a checked exception, you must declare it withthrows InvalidAgeException.verifyAgeUncheckedOnly(int age)- This method only uses unchecked exceptions. If age is negative, throwNegativeAgeExceptionwith the same message format. If age is less than 18, throw anIllegalArgumentExceptionwith message"Too young: [age]". Otherwise, printAge [age] verified (unchecked method). Notice this method needs nothrowsdeclaration!Main.java: Bring your verification system together! You'll receive one input: an age (integer).First, print
=== Checked Exception Method ===and callverifyAgewith the input age. Since it throws a checked exception, you must wrap it in a try-catch. CatchInvalidAgeExceptionand printChecked exception caught: [message]. Also catchNegativeAgeExceptionand printUnchecked exception caught: [message].Then print a blank line and
=== Unchecked Exception Method ===. CallverifyAgeUncheckedOnlywith the same age. Even though this method can throw exceptions, you're not forced to catch them. However, wrap it in a try-catch anyway to handle errors gracefully. CatchNegativeAgeExceptionand printRuntime exception caught: [message]. CatchIllegalArgumentExceptionand printIllegal argument caught: [message].
You will receive one input: an integer representing the age to verify.
Notice the key difference: the method with the checked exception requires a throws declaration and forces callers to handle it, while the unchecked method compiles fine without any exception handling. This is the fundamental distinction between checked and unchecked exceptions in Java!
Cheat sheet
Java exceptions are divided into checked and unchecked exceptions, which determines how the compiler enforces handling them.
Checked exceptions extend Exception directly (not through RuntimeException). The compiler forces you to either catch them or declare them with throws:
// Must declare with throws
public void readFile(String path) throws IOException {
FileReader reader = new FileReader(path);
}
// Or catch it
public void readFileSafe(String path) {
try {
FileReader reader = new FileReader(path);
} catch (IOException e) {
System.out.println("File error: " + e.getMessage());
}
}Unchecked exceptions extend RuntimeException. The compiler doesn't require you to handle them. They typically indicate programming errors:
// No throws declaration needed
public int divide(int a, int b) {
return a / b; // May throw ArithmeticException (unchecked)
}
String name = null;
name.length(); // NullPointerException (unchecked)When creating custom exceptions, choose the parent class based on how callers should handle them:
- Use checked exceptions (extend
Exception) for recoverable conditions the caller should anticipate - Use unchecked exceptions (extend
RuntimeException) for programming errors that shouldn't occur in correct code
Try it yourself
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int age = scanner.nextInt();
// TODO: Test the checked exception method
// Print: "=== Checked Exception Method ==="
// Call AgeVerifier.verifyAge(age) in a try-catch
// - Catch InvalidAgeException: print "Checked exception caught: [message]"
// - Catch NegativeAgeException: print "Unchecked exception caught: [message]"
// TODO: Print a blank line, then "=== Unchecked Exception Method ==="
// Call AgeVerifier.verifyAgeUncheckedOnly(age) in a try-catch
// - Catch NegativeAgeException: print "Runtime exception caught: [message]"
// - Catch IllegalArgumentException: print "Illegal argument caught: [message]"
}
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesIntroduction to OOPClasses vs ObjectsThe this KeywordMethodsFields (Attributes)Constructor MethodConstructor OverloadingRecap - Simple Calculator4Inheritance
Basic Inheritance (extends)The super KeywordMethod Overriding (@Override)Constructor ChainingThe Object ClassSingle & Multilevel InheritWhy No Multi Class InheritRecap - Employee Hierarchy7Special Methods & Object Class
toString() Methodequals() and hashCode()clone() MethodcompareTo() and ComparableComparator InterfaceRecap - Custom Sorting10Exception Handling in OOP
Exception Class HierarchyCustom ExceptionsChecked vs Unchecked ErrorsTry With Resources PatternRecap - Validated User2Access Modifiers & Encapsulate
Access Levels OverviewGetter and Setter MethodsInformation HidingThe final KeywordRecap - Bank Account Manager5Polymorphism
Method Overloading BasicsMethod Overriding (Run-Time)Upcasting and DowncastingThe instanceof OperatorAbstract Classes and MethodsRecap - Shape Calculator8Advanced OOP Concepts
Composition vs InheritanceAggregation vs CompositionInner Nested & Anonymous ClassEnums and Enum MethodsRecords (Java 16+)Sealed Classes (Java 17+)3Class Props & Static Member
Instance vs Static VariablesStatic MethodsStatic BlocksConstants (static final)Recap - Counter & Utility6Interfaces & Abstract Classes
Introduction to InterfacesImplementing InterfacesMulti Interface ImplemenDefault & Static in InterfaceAbstract Classes vs InterfacesFunctional InterfacesRecap - Payment System