Things go wrong even in correct programs: a file might be missing, a network call might time out, or a calculation might divide by zero. An exception is how Java signals that one of these problems occurred, and handling it properly is what keeps a single failure from crashing the entire program.
The try-catch block
try {
int result = 10 / divisor;
} catch (ArithmeticException e) {
System.out.println("Cannot divide by zero");
}Risky code goes inside try. If it throws an exception, execution jumps immediately into the matching catch block instead of crashing the program, and everything after the failing line inside try is skipped.
The finally block
try {
// open a file
} catch (Exception e) {
// handle error
} finally {
// close the file
}Code inside finally always runs, whether or not an exception occurred, making it the natural place for cleanup work such as closing a file or a network connection that must happen no matter what.
Try-with-resources
For anything that implements Closeable, such as file streams, a try-with-resources block closes it automatically once the block finishes, removing the need for a manual finally block entirely:
try (BufferedReader reader = new BufferedReader(new FileReader("data.txt"))) {
String line = reader.readLine();
} catch (IOException e) {
System.out.println("Could not read the file");
}Checked versus unchecked exceptions
Checked exceptions, like IOException, must be declared or caught, and the compiler enforces this. Unchecked exceptions, which extend RuntimeException, such as ArithmeticException or NullPointerException, are not enforced by the compiler and usually point to a programming mistake rather than an unavoidable external failure.
Catching more than one type
try {
// risky code
} catch (IOException | SQLException e) {
System.out.println("A recoverable error occurred: " + e.getMessage());
}Writing a custom exception
Applications often define their own exception types to represent specific problems clearly, rather than reusing a generic one:
public class InsufficientFundsException extends RuntimeException {
public InsufficientFundsException(String message) {
super(message);
}
}Catching the right thing
Catching a specific exception type allows a program to respond appropriately to each distinct problem. Catching a broad Exception hides the real cause and makes debugging much harder later, since it treats every possible failure, no matter how different, as the exact same case.
Do not ignore errors
An empty catch block silently swallows a real problem and makes bugs almost impossible to trace afterward. At an absolute minimum, an error should be logged so there is a record that it happened, even if the program can otherwise continue safely.