Was ist eine Exception?
Exception ist ein Ereignis, das den normalen Ablauf eines Programms unterbricht.
Wenn ein Fehler auftritt, erstellt Java ein Objekt der Klasse Throwable und übergibt es an die Runtime-Umgebung (JVM).
Wenn eine Exception nicht abgefangen wird (try-catch), beendet das Programm mit einem Fehler.
Hierarchie von Throwable
java.lang.Object
└── java.lang.Throwable
├── Exception
│ └── RuntimeException
│ └── ... (andere checked Exceptions)
└── Error📗 Erklärung der Verzweigungen:
| Klasse | Zweck |
|---|---|
Throwable | Basisklasse für alle Fehler und Exceptions |
Error | JVM-Fehler (müssen nicht manuell behandelt werden) – z.B. OutOfMemoryError, StackOverflowError |
Exception | Exceptions, die behandelt werden können (und sollten) |
RuntimeException | Runtime-Exceptions (unchecked) – NullPointerException, ArrayIndexOutOfBoundsException, IllegalArgumentException usw. |
Checked vs Unchecked Exceptions
| Typ | Beispiel | Wann tritt auf | Muss in throws deklariert werden? | Wird behandelt? |
|---|---|---|---|---|
| Checked | IOException, SQLException, FileNotFoundException | Fehler, die zur Kompilierzeit vorhersehbar sind (z.B. bei der Arbeit mit Dateien, Netzwerken) | ✅ Ja | Muss (try-catch oder throws) behandelt werden |
| Unchecked (Runtime) | NullPointerException, IndexOutOfBoundsException, ArithmeticException | Fehler, die während der Laufzeit auftreten (in der Regel aufgrund von Bugs) | ❌ Nein | Kann behandelt werden, ist aber nicht erforderlich |
📙 Beispiel: Checked Exception
import java.io.FileReader;
import java.io.IOException;
public class CheckedExample {
public static void main(String[] args) {
try {
FileReader reader = new FileReader("data.txt");
reader.read();
reader.close();
} catch (IOException e) {
System.out.println("Fehler beim Lesen der Datei: " + e.getMessage());
}
}
}💡 Ohne einen try-catch-Block wird der Code vom Compiler nicht ausgeführt, da FileReader eine IOException auslöst.
📙 Beispiel: Unchecked Exception
public class UncheckedExample {
public static void main(String[] args) {
int[] nums = {1, 2, 3};
System.out.println(nums[5]); // ArrayIndexOutOfBoundsException
}
}💡 Kann kompiliert werden, führt aber bei der Ausführung zu einem Laufzeitfehler.
Blöcke try, catch, finally
✅ Hauptsyntax
try {
// Code, der eine Exception auslösen könnte
} catch (ExceptionType e) {
// Exception behandeln
} finally {
// Wird immer ausgeführt, unabhängig davon, ob eine Exception aufgetreten ist
}📙 Beispiel:
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("Division durch Null!");
} finally {
System.out.println("Ende der Operation");
}Ausgabe:
Division durch Null!
Ende der Operation
💡 finally wird immer ausgeführt, auch wenn im catch ein return enthalten ist.
try-with-resources (Java 7+)
Zweck:
Schließt Ressourcen (z.B. Dateien, Streams, Verbindungen), die die Schnittstelle AutoCloseable implementieren, automatisch.
Syntax:
try (FileReader reader = new FileReader("data.txt")) {
int c = reader.read();
} catch (IOException e) {
e.printStackTrace();
}💡 Nach dem Verlassen des try-Blocks wird die Methode reader.close() automatisch aufgerufen, auch wenn eine Exception auftritt.
📍 Funktioniert mit jedem Objekt, das AutoCloseable oder Closeable implementiert.
Beispiel mit JDBC:
try (Connection conn = DriverManager.getConnection(url);
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}Schlüsselwörter throw und throws
throw – löst eine Exception manuell aus
if (age < 0) {
throw new IllegalArgumentException("Alter darf nicht negativ sein!");
}💡 Wird verwendet, um Fehler im Code zu generieren oder Daten zu validieren.
throws – deklariert, dass die Methode eine Exception auslösen kann
void readFile(String path) throws IOException {
FileReader reader = new FileReader(path);
}💡 Die Deklaration von throws ist erforderlich für checked Exceptions, wenn diese nicht innerhalb der Methode abgefangen werden.
Mehrfache catch-Blöcke
try {
FileReader reader = new FileReader("file.txt");
int x = 10 / 0;
} catch (FileNotFoundException e) {
System.out.println("Datei nicht gefunden");
} catch (ArithmeticException e) {
System.out.println("Divison durch Null");
} catch (Exception e) {
System.out.println("Allgemeiner Fehler");
}📍 catch-Blöcke werden von unten nach oben abgeglichen, von spezifischeren zu allgemeineren.
Mehrfacher catch (Java 7+)
Wenn mehrere Exceptions auf dieselbe Weise behandelt werden sollen, können sie kombiniert werden:
try {
// ...
} catch (IOException | SQLException e) {
e.printStackTrace();
}Erstellung eigener Exceptions
Es ist möglich, eine eigene Exception zu erstellen, indem man von Exception oder RuntimeException erbt.
Checked Custom Exception:
class MyCheckedException extends Exception {
public MyCheckedException(String message) {
super(message);
}
}Unchecked Custom Exception:
class MyRuntimeException extends RuntimeException {
public MyRuntimeException(String message) {
super(message);
}
}📍 Unterschied:
- Vererbt
Exception→ mussthrowsdeklariert werden. - Vererbt
RuntimeException→ kann nicht deklariert werden.
Typische Fehler
❌ Exceptions ignorieren:
try {
doSomething();
} catch (Exception e) {
// leer – schlecht!
}✅ Besser:
try {
doSomething();
} catch (Exception e) {
log.error("Fehler bei der Ausführung", e);
throw e; // oder in eine eigene Exception verpacken
}❌ Falsche Reihenfolge der catch-Blöcke:
try { ... }
catch (Exception e) { ... }
catch (IOException e) { ... } // unerreichbarer Code✅ Richtig – von spezifisch zu allgemein.
⚙️Best Practices
- ✅ Verwende
try-with-resourcesfür alle IO/JDBC-Operationen. - ✅ Fange nur die Exceptions ab, die sinnvoll behandelt werden können.
- ✅ Verwende
ExceptionoderThrowableimcatchohne Grund nicht. - ✅ Erstelle eigene Exceptions für die Geschäftslogik.
- ✅ Verwende Exceptions nicht für den normalen Kontrollfluss.
- ✅ Protokolliere immer Fehler (
Logger,SLF4J,Logbackusw.).