Bad Practice: Verschlucken der Ursprungs-Exception bei catch/finally

22.07.2023

Jeder Java-Entwickler dürfte try, catch und finally kennen. Aber was passiert, wenn im catch- oder im finally-Block eine neue Exception fliegt? Was müssen wir beachten, damit Fehlersuche hier nicht zum Albtraum wird? Welche Sprachmittel stellt uns Java hier zur Verfügung und welche Variante ist die beste?

Code-Beispiel

Um die Situation darzustellen, simulieren wir zunächst eine Business-Logik, die eine Exception werfen kann. Außerdem haben wir zwei Methoden, die das Senden einer Benachrichtigung simulieren. Eine der beiden wirft selbst eine Exception.

Im Folgenden betrachten wir nun zwei Beispiele:

  1. Im ersten Beispiel wird im finally-Block die Benachrichtigungsmethode aufgerufen.
  2. Im zweiten Beispiel wird die Benachrichtigungsmethode in einem catch-Block aufgerufen. Damit im zweiten Beispiel ebenfalls auch im Erfolgsfall eine Benachrichtigung erfolgt, rufen wir zusätzlich nach der Business-Logik die Benachrichtigungsmethode auf, die keine Exception wirft. So sind die beiden Beispiele in etwa vergleichbar.

1) Beispiel mit finally-Block

In diesem ersten Beispiel sieht der Aufrufende folgenden Stacktrace:

2) Beispiel mit catch-Block

Hier sieht der Stacktrace wie folgt aus:

Beobachtung

Wir sehen: In beiden Fällen wird die ursprüngliche Exception verschluckt. Dies ist irreführend und erschwert die Fehlersuche enorm.

Lösungsmöglichkeiten

Doch wie können wir das besser machen? Der Rest des Artikels stellt folgende drei Lösungsmöglichkeiten dar:

  1. Fangen und Loggen der Exception, die im Finally- oder im Catch-Block auftritt
  2. Die Exception aus dem Catch-Block mittels addSuppressed zur ursprünglichen Exception hinzufügen
  3. try-with-resources und Autocloseable verwenden (beste Lösung)

Lösung 1: Fangen und Loggen der Exception, die im Finally- oder im Catch-Block auftritt

Im finally-Beispiel

Das sieht der Aufrufende:

Die Exception aus dem finally-Block ist nur im Log-File zu sehen:

Im catch-Beispiel

Das sieht der Aufrufende:

Die Exception aus dem catch-Block ist nur im Log-File zu sehen:

Beobachtung

Beide Beispiele verhalten sich nun gleich und der Aufrufende sieht die ursprüngliche Exception. Das ist gut. Aber die Exception aus dem Catch- / Finally-Block ist nur im Log-File zu sehen. Eine meist bessere Möglichkeit, die aber nur für das Catch-Beispiel funktioniert, ist addSuppressed:

Lösung 2: Die Exception aus dem Catch-Block mittels addSuppressed zur ursprünglichen Exception hinzufügen

Das sieht der Aufrufende:

Beobachtung

Der Aufrufende hat nun alle Fehlerinformationen, auch die unterdrückte Exception aus dem Catch-Block. Dies ist schon viel besser. Leider funktioniert diese Variante nur für das catch-Beispiel. Außerdem ist die Business-Logik zwischen einer Menge Fehlerbehandlungs-Code versteckt. Schöner wäre es, wenn wir Fehlerhandling und Business-Logik besser trennen könnten.

Lösung 3: try-with-resources und Autocloseable verwenden (beste Lösung)

Zunächst machen wir unsere Business-Logik Autocloseable. Dies kann z. B. durch eine Wrapper-Klasse geschehen.

Dies ist zwar zunächst etwas Mehraufwand, aber der eigentliche Aufruf der Business-Logik sieht dann sehr sauber aus und trennt Business-Logik von Exception-Handling (Separation of Concerns).

Außerdem muss man sich nun nicht mehr selbst um das Hinzufügen der unterdrückten Exception kümmern. Dies geschieht nun automatisch. Ebenso wie in Lösung 2 hat der Aufrufer nun alle Fehlerinformationen – auch die unterdrückte Exception.

Fazit

Die eleganteste Lösung ist es, Autocloseable und try-with-resources einzusetzen. Denn:

  • Dies fokussiert auf die Business-Logik (Separation of Concerns).
  • Ressourcen werden dort geschlossen, wo sie geöffnet werden, was die Verständlichkeit und die Wartbarkeit verbessert.
  • Tritt beim Schließen eine Exception auf, wird automatisch addSuppressed verwendet. Die Ursprungs-Exception wird nicht verschluckt.

Bildnachweis:
– Das Titelbild zur Blogserie „Exception Handling“ basiert auf einer Grafik von mohamed_hassan auf Pixabay.

Zurück zur Übersicht

Kommentar verfassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

*Pflichtfelder

*