RU | EN | DE

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:

KlasseZweck
ThrowableBasisklasse für alle Fehler und Exceptions
ErrorJVM-Fehler (müssen nicht manuell behandelt werden) – z.B. OutOfMemoryError, StackOverflowError
ExceptionExceptions, die behandelt werden können (und sollten)
RuntimeExceptionRuntime-Exceptions (unchecked) – NullPointerException, ArrayIndexOutOfBoundsException, IllegalArgumentException usw.

Checked vs Unchecked Exceptions

TypBeispielWann tritt aufMuss in throws deklariert werden?Wird behandelt?
CheckedIOException, SQLException, FileNotFoundExceptionFehler, die zur Kompilierzeit vorhersehbar sind (z.B. bei der Arbeit mit Dateien, Netzwerken)✅ JaMuss (try-catch oder throws) behandelt werden
Unchecked (Runtime)NullPointerException, IndexOutOfBoundsException, ArithmeticExceptionFehler, die während der Laufzeit auftreten (in der Regel aufgrund von Bugs)❌ NeinKann 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 → muss throws deklariert 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-resources für alle IO/JDBC-Operationen.
  • ✅ Fange nur die Exceptions ab, die sinnvoll behandelt werden können.
  • ✅ Verwende Exception oder Throwable im catch ohne Grund nicht.
  • ✅ Erstelle eigene Exceptions für die Geschäftslogik.
  • ✅ Verwende Exceptions nicht für den normalen Kontrollfluss.
  • ✅ Protokolliere immer Fehler (Logger, SLF4J, Logback usw.).