1. Class Throwable: the root of all exceptions
Now we will take a close look at how Java’s exception system is structured: what Throwable is, how Exception differs from Error, and what “checked” and “unchecked” exceptions mean. This is the foundation for proper error handling in your programs.
In Java, all exceptions and errors are objects that inherit from the class java.lang.Throwable.
Throwable is the “ancestor” of the entire hierarchy for handling problems in Java.
Schematic:
Throwable
├── Exception
└── Error
Throwable is the base class for everything that can be “thrown” (throw) and “caught” (catch) in Java. You don’t use it directly—it serves as the foundation for more specific error types.
Exception — for “normal” errors
Exception is the base class for all exceptions that can occur in a program and that you can and should handle. These are operational errors: problems with files, networking, I/O, user mistakes, etc. Most of your try-catch blocks will deal with subclasses of Exception.
Examples:
- IOException — error when working with files or the network.
- SQLException — error when working with a database.
- FileNotFoundException — file not found.
Error — for fatal JVM errors
Error is the base class for errors that occur at the Java Virtual Machine (JVM) level. These are usually critical failures that the program cannot and should not handle. If an Error occurs, the application most likely cannot continue running.
Examples:
- OutOfMemoryError — out of memory.
- StackOverflowError — stack overflow (for example, due to infinite recursion).
- NoClassDefFoundError — required class not found.
Important:
Catching and handling Error is almost always a bad idea. These are not your program’s errors but runtime environment failures.
2. Checked vs unchecked exceptions: what does it mean?
In Java, all exceptions fall into two large groups:
Checked exceptions
What are they? Exceptions that the compiler forces you to handle or explicitly rethrow.
When do they occur? They are usually associated with external resources: files, networking, databases, user input.
How to handle? Either wrap the code in try-catch, or add throws to the method signature.
Examples: IOException, SQLException, FileNotFoundException
Example:
public void readFile(String path) throws IOException {
FileReader reader = new FileReader(path); // can throw IOException
// ...
}
If you neither handle nor rethrow—the program will not compile!
Unchecked exceptions
What are they? Exceptions that the compiler does not require you to handle.
When do they occur? Usually these are program logic errors: division by zero, going out of array bounds, dereferencing null.
How to handle? You can catch them, but you don’t have to. It’s better to prevent such errors with checks.
Where in the hierarchy? They all inherit from RuntimeException.
Examples: NullPointerException, ArrayIndexOutOfBoundsException, IllegalArgumentException, ArithmeticException
Example:
int[] arr = {1, 2, 3};
System.out.println(arr[10]); // ArrayIndexOutOfBoundsException
The compiler does not force you to catch this exception—but the program will crash on error.
3. The whole hierarchy in one picture
graph TD
Throwable --> Error
Throwable --> Exception
Exception --> RuntimeException
Exception --> CheckedExceptions["(other checked exceptions)"]
Error --> OutOfMemoryError
Error --> StackOverflowError
RuntimeException --> NullPointerException
RuntimeException --> IndexOutOfBoundsException
RuntimeException --> IllegalArgumentException
%% Styles
style Throwable fill:#ffa64d,color:#000
style Exception fill:#ffa64d,color:#000
style CheckedExceptions fill:#ffa64d,color:#000
style Error fill:#ff4d4d,color:#fff
style OutOfMemoryError fill:#ff4d4d,color:#fff
style StackOverflowError fill:#ff4d4d,color:#fff
style RuntimeException fill:#4dff88,color:#000
style NullPointerException fill:#4dff88,color:#000
style IndexOutOfBoundsException fill:#4dff88,color:#000
style IllegalArgumentException fill:#4dff88,color:#000
Table: key differences
| Group | Parent class | Requires handling? | Examples |
|---|---|---|---|
| Checked Exception | |
Yes | |
| Unchecked | |
No | |
| Error | |
No | |
4. What does it look like in code?
Checked exception: example with files
import java.io.*;
public class FileDemo {
public static void main(String[] args) {
try {
FileReader reader = new FileReader("nofile.txt"); // FileNotFoundException (checked)
int data = reader.read();
System.out.println(data);
reader.close();
} catch (IOException e) {
System.out.println("Error working with file: " + e.getMessage());
}
}
}
The compiler will make you handle IOException!
Unchecked exception: example with division by zero
public class ExceptionDemo {
public static void main(String[] args) {
int a = 10;
int b = 0;
int c = a / b; // ArithmeticException (unchecked)
System.out.println("Result: " + c);
}
}
The compiler does not require handling, but the program will crash.
5. Why do we need an exception hierarchy?
- Flexible handling: You can catch both specific errors (FileNotFoundException) and whole groups (IOException or Exception).
- Code reuse: You can handle errors of one type centrally.
- Cleaner code: The main logic isn’t cluttered with checks for every little thing.
Example:
try {
// risky code
} catch (FileNotFoundException e) {
System.out.println("File not found!");
} catch (IOException e) {
System.out.println("I/O error!");
} catch (Exception e) {
System.out.println("Something went wrong: " + e.getMessage());
}
6. Common mistakes when working with exceptions
Mistake #1: Ignoring exceptions. Writing catch (Exception e) {} is bad! You lose information about the cause of the error.
Mistake #2: Catching too much. catch (Exception e) catches everything, even what you didn’t expect. It’s better to catch only the exceptions you know how to handle.
Mistake #3: Catching errors (Error). You should not catch Error unless you are writing low-level code. These are JVM issues, not your program’s.
Mistake #4: Not distinguishing checked and unchecked. Not all exceptions are the same! Checked ones require handling (Exception), unchecked ones do not (RuntimeException and its descendants).
Mistake #5: Not adding information to exceptions. If you create your own exceptions—always add an informative message.
GO TO FULL VERSION