An exception in Java is an event that occurs during program execution, disrupting the normal flow of instructions. When unhandled, it causes abrupt termination.
Java provides a robust mechanism to manage such disruptions, allowing programs to recover gracefully or log meaningful diagnostics instead of crashing.
Core Exception Handling Constructs
The try-catch-finally block forms the foundation:
public class CalculationExample {
public static void main(String[] args) {
int numerator = 20;
int denominator = 0;
System.out.println("Initiating division...");
try {
int quotient = numerator / denominator;
} catch (ArithmeticException ex) {
System.err.println("Division by zero detected: " + ex.getMessage());
}
System.out.println("Execution continues normally.");
}
}
Multiple exceptions can be addressed using cascaded catch clauses — ordered from most specific to most general:
import java.util.Scanner;
public class InputProcessor {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Enter first integer: ");
String s1 = input.nextLine();
System.out.print("Enter second integer: ");
String s2 = input.nextLine();
try {
int x = Integer.parseInt(s1);
int y = Integer.parseInt(s2);
int result = x / y;
System.out.println("Result: " + result);
} catch (NumberFormatException nfe) {
System.err.println("Invalid numeric format: " + nfe.getMessage());
} catch (ArithmeticException ae) {
System.err.println("Mathematical error: " + ae.getMessage());
}
}
}
Exception Hierarchy and Propagation
All exceptions inherit from Throwable. The two primary subclasses are:
Error: Indicates serious problems beyond application control (e.g.,OutOfMemoryError).Exception: Represents conditions that applications may reasonably handle. Subdivided into:- Checked exceptions (e.g.,
IOException) — enforced at compile time. - Unchecked exceptions (e.g.,
NullPointerException,IllegalArgumentException) — extendRuntimeExceptionand are not enforced.
- Checked exceptions (e.g.,
The throws clauce delegates responsibility for checked exceptions to callers:
public class DivisionService {
public static int divide(int a, int b) throws ArithmeticException {
if (b == 0) {
throw new ArithmeticException("Divisor cannot be zero");
}
return a / b;
}
public static void main(String[] args) {
try {
int outcome = divide(10, 0);
} catch (ArithmeticException e) {
System.err.println("Handled upstream: " + e.getMessage());
}
}
}
Key Exception Methods
Every Throwable enstance offers diagnostic utilities:
getMessage()→ returns the detail message string.toString()→ combines class name and message.printStackTrace()→ outputs full stack trace to standard error.
Guaranteed Cleanup with finally
Code inside finally always executes — whether an exception occurred, was caught, or even if a return statement appears in try or catch:
public class ResourceDemo {
public static int compute() {
int value = 5;
try {
return value * 2;
} finally {
System.out.println("Cleanup logic executed regardless.");
// Note: Avoid returning here unless intentional — it overrides prior return.
}
}
public static void main(String[] args) {
System.out.println("Final value: " + compute());
}
}
A try block may pair with finally alone (no catch) when cleanup is needed but no local handling is required.
Manual Exception Throwing with throw
Use throw to explicitly raise exceptions, often for validating preconditions:
public class Person {
private String fullName;
private int yearsOld;
public void setAge(int age) {
if (age < 0 || age > 150) {
throw new IllegalArgumentException("Age must be between 0 and 150");
}
this.yearsOld = age;
}
}
Creating Custom Exceptions
When built-in types lack sementic clarity, define domain-specific exceptions:
public class InvalidAgeException extends IllegalArgumentException {
public InvalidAgeException(String reason) {
super("Invalid age specification: " + reason);
}
}
// Usage
public void validateAge(int candidateAge) {
if (candidateAge < 0) {
throw new InvalidAgeException("negative value supplied");
}
}
Custom exceptions improve readability, maintainability, and enable precise catch targeting across layered architectures.