An exception is an object that represents an anomalous situation and alters the normal flow of the program.
So far, we have programmed mainly thinking about the correct path: that the file exists, the user enters valid data, and the network responds. But reality is harsh. Software fails.
In Java, when something interrupts the normal execution flow, an Exception is thrown. If we don’t catch it, the program crashes and displays the dreaded Stack Trace (that wall of red text in the console).
Today we are going to understand Java’s error architecture, because it has a peculiarity that no other modern language has: the distinction between errors you are forced to catch and those you are not.
The Throwable hierarchy
In Java, an error is not a numeric code (like in C). An error is an Object.
All errors descend from the parent class java.lang.Throwable. Two main branches with very different philosophies hang from it.
Branch 1: Error
These represent serious problems with the Java Virtual Machine (JVM). They are situations from which it is impossible to recover.
- Examples:
OutOfMemoryError(you ran out of RAM),StackOverflowError(infinite recursive loop).
Important: In application code, you should normally not catch Error. It represents serious JVM or environment problems that can rarely be safely recovered from.
Branch 2: Exception
This is where we work. They represent program errors or external factors (files, databases) from which we could actually recover.
- Examples:
IOException,NullPointerException,SQLException.
The great debate: checked vs unchecked
Within the Exception branch, Java makes a distinction that defines the language’s personality.
Checked exceptions
These are exceptions that the Compiler FORCES you to handle.
If you use a method that throws a Checked Exception, the code will not compile unless you do one of two things:
- Wrap it in a
try-catch(Fix it). - Add
throwsto your method (Pass the problem to the caller).
Java assumes these are “foreseeable” errors and wants to make sure you don’t forget about them.
- Which ones are they? Any class that inherits from
Exceptionbut NOT fromRuntimeException. - Example:
FileNotFoundException. If you try to open a file, Java yells at you: “Hey! What if the file isn’t there? Tell me what to do!”.
Unchecked exceptions
These are exceptions that occur at runtime and the compiler does not warn you about. You are not obligated to catch them (although you should avoid them).
They usually represent programming failures (bugs) or logic errors.
- Which ones are they? All that inherit from
RuntimeException. - Example:
NullPointerException. Java does not force you to put atry-catchevery time you use an object in case it isnull, because the code would be unreadable. It is assumed that, as a programmer, you have checked that it is not null beforehand.
Comparison table
| Type | Checked | Unchecked (Runtime) | Error |
|---|---|---|---|
| Base Class | Exception | RuntimeException | Error |
| Origin | External factors (Network, IO). | Programmer logic (Bugs). | Critical JVM environment. |
| Compiler | Forces you to handle them. | Ignores you. | Ignores you. |
| Examples | IOException, SQLException. | NullPointer, IndexOutOfBounds. | OutOfMemoryError. |
| Action | Recover (retry, notify). | Fix the code (the bug). | Restart the app. |
The “handle or declare” principle
When you face a Checked Exception, you have to make a design decision.
Imagine a method that reads a file:
import java.io.FileReader;
import java.io.File;
public void leerFichero() {
File f = new File("notas.txt");
// The following line shows COMPILATION ERROR
// FileReader throws FileNotFoundException (Checked)
FileReader fr = new FileReader(f);
}
You have two options:
Option A: Handle
Use try-catch to solve the problem right there.
public void leerFichero() {
try {
FileReader fr = new FileReader(new File("notas.txt"));
} catch (FileNotFoundException e) {
System.out.println("The file does not exist. Creating a new one...");
}
}
Option B: Declare Wash your hands of it and say that your method might fail. Whoever calls your method will have to deal with it.
// Add 'throws' to the signature
public void leerFichero() throws FileNotFoundException {
FileReader fr = new FileReader(new File("notas.txt"));
}