Show TOC Anfang des Inhaltsbereichs

Hintergrunddokumentation Die Ausnahmebehandlung planen und Ausnahmen delegieren Dokument im Navigationsbaum lokalisieren

Ausnahmen abfangen und behandeln

Ein TRY-ENDTRY-Konstrukt kann mehrere Behandler enthalten, und in einem Behandler können Sie Ausnahmen unterschiedlicher Klassen fangen. Weiterhin fangen Sie mit den Ausnahmen einer Klasse auch alle Ausnahmen von Unterklassen dieser Klasse. Auf diese Weise ist eine gruppierte Behandlung von Ausnahmen möglich. So können Sie sich beispielsweise dafür entscheiden, unterschiedliche Ausnahmen zu werfen je nachdem, ob eine Adresse zu einem Kunden nicht vorhanden, fehlerhaft oder mehrfach vorhanden ist, aber all diesen Ausnahmen eine gemeinsame Oberklasse zu geben und diese Oberklasse dann zu fangen.

Sie fangen eine Ausnahme in einem CATCH-Satz, der den Namen der entsprechenden Ausnahmeklasse oder einer Klasse weiter oben in der Vererbungshierarchie enthält. Nur wenn Sie eine Ausnahme gefangen haben, können Sie sie behandeln. In einem Behandler sollten Sie etwas tun, um angemessen auf den Fehler zu reagieren und den weiteren semantisch sinnvollen Programmablauf sicherzustellen. In einem modularisierten Programm ist das allerdings nicht immer dort möglich, wo die Ausnahme auftritt.

Die Ausnahmebehandlung delegieren

Stellen Sie sich vor, Sie schreiben eine Service-Klasse, die Adressdaten auf der Datenbank verwaltet. Eine Methode bekommt den Schlüssel eines speziellen Business-Objekts und soll die entsprechenden aus der Datenbank auslesen. Wenn Sie keine Adresse finden, so sollten Sie eine Ausnahme werfen, diese aber nicht an Ort und Stelle in Ihrer Methode behandeln. Wie sollten Sie das auch sinnvoll tun. Sie wissen nicht, was der Aufrufer mit diesen Adressdaten tun will, ob sie nur eine zusätzliche Information, etwa für die Agenten eines Call-Centers sind oder ob ohne sie der weitere Programmablauf stark abgeändert werden muss, wie beispielsweise im Fall einer Lieferung, für die eine Liederadresse essentiell ist.

Ausnahmen an der Schnittstelle deklarieren

Deshalb ist es wichtig, dass Sie als Entwickler modularisierter Einheiten Ausnahmen an den Aufrufer delegieren können. Die Weitergabe nach oben in der Aufrufhierarchie, genannt Propagierung, von Ausnahmen erfolgt automatisch, wenn eine Ausnahme nicht in dem TRY-ENDTRY-Konstrukt behandelt wird, wo sie ausgelöst wurde. Allerdings müssen Ausnahmen an der Schnittstelle einer Prozedur (Methode, Unterprogramm, Funktionsbaustein) deklariert sein. Sonst bekommen Sie zur Designzeit einen Syntaxfehler, und zur Laufzeit die Ausnahme CX_SY_NO_HANDLER. Die Laufzeitumgebung stellt auf diese Weise sicher, dass nur deklarierte Ausnahmen eine Prozedur verlassen können (besondere Ausnahmen von dieser Regel werden später erklärt).

Warum die Deklarationspflicht für Ausnahmen? Der Aufrufer einer Methode muss wissen, mit welchen Ausnahmen er zu rechnen hat. Als Aufrufer wird er sich üblicherweise nicht um das Innenleben der aufgerufenen Methode kümmern und noch viel weniger um die ihrerseits dort wieder aufgerufenen Methoden. Die Deklaration an der Schnittstelle stellt sicher, dass Sie als Aufrufer einer Prozedur sicher sein können, welche Ausnahmen Sie behandeln oder Ihrerseits weitergeben müssen.

Der CLEANUP- Block

Falls Sie eine Ausnahme nicht in Ihrer Programmeinheit behandeln und der Kontrollfluss in der Aufrufhierarchie von der Auslösestelle direkt weiter oben an eine Stelle springt, wo der Fehler behandelt wird, hinterlassen Sie die Programmeinheit unter Umständen in einem inkonsistenten Zustand oder belegen bestimmte Ressourcen weiter. Für solche Situationen ist der CLEANUP-Block gedacht. Der CLEANUP-Block eines TRY-ENDTRY-Konstrukts wird nur dann prozessiert:

·        Wenn eine Ausnahme im geschützten Bereichs dieses Konstrukts geworfen wird,

·        Wenn die Ausnahme nicht in diesem Konstrukt behandelt wird, es aber einen Behandler weiter oben in der Aufrufhierarchie gibt. Wenn die Ausnahme überhaupt nirgendwo gefangen wird, ist es wichtig, keine Spuren des Fehlers zu verwischen. Deshalb wird in diesen Fällen der CLEANUP-Block nicht abgearbeitet.

Versuchen Sie auf keinen Fall, einen CLEANUP-Block vorzeitig mit RETURN, EXIT oder CONTINUE zu verlassen. Der CLEANUP-Block wird auf der Basis der Zusage ausgeführt, dass der Fehler weiter oben behandelt wird. Ihn vorzeitig zu verlassen, könnte bedeuten, dass diese Zusage verletzt wird. Aus diesem Grund bekommen Sie zu Laufzeit einen Laufzeitfehler, wenn Sie versuchen einen CLEANUP-Block irregulär zu verlassen.

Ausnahmebehandlung lokal planen:

Wenn Sie wieder verwendbare Software schreiben, sollten Sie die Ausnahmebehandlung nur für die Programmeinheit planen, die Sie schreiben. Vermeiden Sie, soweit es möglich ist, spezielle Annahmen über die Schichten, von denen Sie aufgerufen werden, und die von Ihnen gerufenen, die über den im Interface spezifizierten Kontrakt hinausgehen. Die Implementierung dieser Schichten kann sich ändern, und dann würde Ihre Ausnahmebehandlung unter Umständen nicht mehr korrekt funktionieren, wenn sie von Annahmen über das Innenleben dieser Schichten abhinge, die zu einem späteren Zeitpunkt nicht mehr bestehen.

Sie sollten lediglich für Ihre Prozedur entscheiden: Welche der Ausnahmen, die Sie werfen oder von unten bekommen, wollen Sie behandeln und welche delegieren bzw. technisch gesprochen propagieren? Wenn Sie eine Ausnahme behandeln, seien Sie vor allem vorsichtig mit Nachrichten oder anderen Arten, Informationen ans User Interface zu geben. Verzichten Sie darauf, wenn Sie nicht vollkommen sicher sind, dass Ihre Programmeinheit das User-Interface bildet.

Was tun im Behandler?

Selbstverständlich behandeln Sie in einem Behandler die Ausnahme. Was Sie im Einzelfall tun kann allerdings ganz verschiedene Ausprägungen annehmen. Eine Analogie zu Störungen einer Reise hilft zu verdeutlichen, worin eine geeignete Ausnahmebehandlung bestehen kann. Stellen Sie sich vor, Sie können Ihre Reiseroute nicht wie geplant fortsetzen, weil eine Brücke über den Fluss gesperrt ist. Das ist die Fehlersituation. Wie können Sie reagieren:

·        Sie können eine andere Brücke nehmen und das Tagesziel trotz des Umwegs dennoch erreichen. Die Analogie im Fall des Programms würde darin bestehen, Werte eines Caches, die Sie brauchen, neu zu berechnen.

·        Sie können diese Tagestour abbrechen und damit weitermachen, was Sie für den nächsten Urlaubstag geplant haben. Wenn eine bestimmte ERP-Anwendung mit der Auflistung einer Lieferung nicht weitermachen kann, weil der Preis eines Produkts fehlt, kann der Kontrollfluss das Programm einfach mit dem nächsten Produkt fortsetzen.

·        Falls weit und breit keine andere Brücke in Sicht ist und die ganze weitere Reise nicht sinnvoll ist, weil Sie den Fluss nicht überschreiten können, werden Sie unter Umständen den gesamten Urlaub abbrechen. Dies kann man mit dem Fall vergleichen, in dem ein so schwerer Fehler im Programmablauf aufgetreten ist, dass es die beste Entscheidung ist, das Programm zu beenden.

Für eine Sache, die Sie im Behandler häufiger tun werden, gibt es in dieser Analogie keine Entsprechung: Manchmal bekommen Sie eine Ausnahme mit einem sehr technischem Text und wollen Sie weiter nach oben in die Aufrufhierarchie geben, wo Sie einen Text benötigen, den der Endnutzer verstehen kann. In diesem Fall fangen Sie die ursprüngliche Ausnahme, werfen eine neue Ausnahme mit einem für den Endnutzer verständlichen Text und hängen eine Referenz an die alte Ausnahme als zusätzliches Attribut an die neue Ausnahme. Man spricht in solchen Fällen davon, eine Ausnahme auf eine andere abzubilden.

Seien Sie generell zurückhaltend damit, Informationen über eine Ausnahme an den Benutzer geben zu wollen, wenn Sie sich nicht vollkommen sicher sind, dass Ihre Komponente, die Sie schreiben, in einer dafür geeigneten Schicht ist. Falls Ihre Komponente weit entfernt vom User Interface aufgerufen wird, ist es sicherlich keine gute Strategie, im Falle einer Ausnahme einen Text direkt an den Benutzer ausgeben zu wollen. In diesem Fall könnten Sie die technische Seite der Ausnahme behandeln und eine Ausnahme mit einem neuen Text weiter nach oben delegieren.

Ende des Inhaltsbereichs