Fehlerbehandlung und Ausnahmen in Java: Eine ausführliche Anleitung
What is it and why? (a real-life analogy)
Imagine you are a head chef in a large kitchen. You are preparing a complex dish according to a recipe. Everything is going according to plan: you chop vegetables, boil broth, add spices. But suddenly — bang! — you run out of salt. Or the blender breaks. Or you accidentally drop a plate of sauce.
What happens if you simply ignore these problems? You continue cooking without salt — the dish will be tasteless. You try to whip cream with a broken blender — it won't whip. You don't notice the broken plate — shards will get into the guests' food. Disaster!
The same thing happens in programming. Your program is a recipe. It executes commands step by step. But in the real world, everything can go off-plan:
- The file you need to read might not exist
- The user might enter letters instead of numbers
- The internet might disconnect while loading data
- Memory might run out
If the program simply ignores these problems, it will either produce an incorrect result or crash (terminate abnormally). Neither is suitable for a serious application.
Error and exception handling is a system that allows a program to:
- Detect the problem (catch the moment when something goes wrong)
- React to it (execute special code for this case)
- Continue working (not crash, but move on, or at least terminate gracefully)
Important: Error handling is not about how to avoid problems. It's about how to gracefully meet a problem when it has already happened. A good programmer always assumes that something can go wrong.
Let's return to our kitchen. An experienced chef always keeps a supply of ingredients, spare tools, and a contingency plan. If the blender breaks — he gets out a hand whisk. If he runs out of salt — he uses soy sauce. If a plate falls — he stops, cleans up the shards, and starts over with clean dishes.
Similarly, a program with good error handling does not crash at the first problem. It catches the exceptional situation, handles it, and continues working. Or, if the problem is critical, it at least informs the user in clear language what happened, and terminates gracefully, saving all data.
In Java, there is a special mechanism for this — exceptions. Let's figure out how it works internally.
Theory: how it works internally
Imagine your program is a multi-story building. Each method is a floor. The program starts execution on the first floor (the main method), calls a method on the second floor, which calls a method on the third floor, and so on. This is called the call stack.
When an error occurs, Java creates a special object — an exception. This object contains all the information about the problem: what happened, where it happened (on which floor and in which line of code), and what the call stack looked like at that moment.
Now this exception object starts rising up through the floors. It leaves the current method and moves to the floor below (the method that called the current one). If no one catches it there either, it rises even lower. And so on all the way down to the first floor — the main method.
If the exception reaches the very bottom (the main method) and no one catches it there either, the program terminates abnormally. Java prints a huge red text to the console with a description of the error and the call stack (this is called a stack trace).
To prevent this, we can catch the exception on any floor. For this, the try-catch construct is used:
- try — this is a block of code where we suspect an error might occur
- catch — this is a block of code that catches the exception and handles it
When an exception occurs inside the try block, the execution of that block immediately stops. Java checks: is there a suitable catch block? If there is, control is transferred to it. If not, the exception flies further up the stack.
In Java, there is a whole hierarchy of exception classes. They all inherit from the Throwable class. The main branches are:
| Class | Description | Example |
|---|---|---|
Error |
Critical problems that the program usually cannot handle | OutOfMemoryError (ran out of memory) |
Exception |
Exceptions that the program can and should handle | IOException (input/output error) |
RuntimeException |
Runtime exceptions (can be left unhandled, but it's better to handle them) | NullPointerException (accessing null) |
Exceptions are divided into two types:
- Checked — descendants of
Exception, but notRuntimeException. The compiler forces you to handle them or declare them in the method signature (throws). Example:IOException,SQLException. - Unchecked — descendants of
RuntimeExceptionandError. The compiler does not require you to handle them, but they can occur at any moment. Example:NullPointerException,ArithmeticException.