Leider findet man über das
Exception-Handling tatsächlich nur wenig konzeptionelle Literatur.
Exceptions = Ausnahmen beziehen sich nicht ausschließlicher Weise nur auf eine Fehlerbehandlung. Dies zeigte besonders der Fall mit EConnectionClosedGracefully der
Indy Komponenten. Diese
Exception ist eine reine Ausnahme und kein Fehler. Logisch gesehen also absolut korrekt aber für viele Programmierer eher unlogisch im Programablauf. Denoch haben die Programmierer von
Indy exakt richtig gehandelt wenn man das Verhalten und die Auswirkungen einer
Exception betrachtet.
Die wichtigste Auswirkung einer
Exception ist das sofortige Abbrechen der auslösenden Funktion und sogar der übergeordneten aufrufenden Funktionen. In den meisten
VCL basierten Programmen springt der Programablauf bis zum obersten Message-Handler. Diese Wirkweise ist eine Wirkung mit sehr harten Konsequenzen im Programablauf und bedingt auch die Schaffung von technischen Maßnahmen bestimmte Codebereich denoch ausführen zu lassen. Somit kommt man sofort und logischersweise von der Möglichkeit Exceptions auslösen zu können, zu der Notwendigkeit mit try finally Blöcken diese Logik kanalisieren zu können. Konkret heist dies, arbeitet man mit Exceptions so muß man auch mit try finally's arbeiten. Da ein Coder der auf fremden Code aufbaut nie wissen kann ob Exceptions ausgelösst werden, muß der Coder nun immer mit try finally's arbeiten.
Hat man nun die Konsequenzen des
Exception Handlings verstanden so erkennt man sehr schnell das die generelle Anwendung von Exceptions in allen Funktionen zu einer Idiotie ausarten kann. Man muß also die gute Balance finden in wie weit man Exceptions anwendet, sprich die Verhältnissmäßigkeit der Wahl der Mittel. Dazu kann man einige Pi*Daumen Regeln anwenden:
Man teilt den Programfluß dreistufig in einfache Lowlevel Funktionen, komplexere Highlevel Funktionen und
GUI Funktionen auf. Normalerweise rufen
GUI Funktionen wie Events, Messages nur die komplexeren Highlevel Funktionen auf. Diese wiederum die Lowlevel Funktionen. Nun, die Lowlevel Funktionen sollten
Exception-frei sein, ausgenommen es werden deren Parameter überprüft (wo aber Assertions besser geeignet wären). Die High-Level Funktionen sollten mit Exceptions arbeiten da deren Programmierung von aussagekräftigen Funktionsrückgabewerten viel zu kompliziert werden kann. D.h. die Exceptions würden innerhalb dieser Highlevel Funktionen deren Aufbau wesentlich erleichtern. Die Programmierung von Rückgabewerten, wie zB. HResult bei Interfaces ist dagegen viel viel mehr Code Overhead und erhöht den Aufwand in der Codierung im Vergleich zu Exceptions.
Im Grunde sind Exceptions nichts anderes als Harte Exits mit einem aussagekräftigem Grund für den Exit.
Wenn EXIT die Antwort und technische Krücke der Prozeduralen Programmierung ist, dann sind die
Exception die Antwort auf diese EXIT's aus Sicht der
OOP.
Soweit so klar. Das was nun das Auslösen von Exceptions so kompliziert macht ist deren gezielte Abarbeitung, d.h. also die Anwendung von try except end Blöcken. Die Sinnhaftigkeit von
Exception bleibt nur gewahrt wenn man nicht permanent in High/Lowlevel Funktionen leere try except Blöcke codiert. D.h. die Anwendung von try except Blöcken sollte ganz genau überlegt werden und wenn angewendet dann müssen sie ganz gezielt nur auf einige
Exception Typen reagieren. WARUM ?? Das Ziel des Exceptions Handlings sollte es sein für den Programmierer aussagekräftige Ausnahmebedingung vom normalen Programmfluß zu visualisieren. Werden die try except Blöcke unüberlegt angewendet so heist dies das man dieses Ziel nicht erreichen kann, der Vorteil der Exceptions geht also verloren !!
Also in kurz:
Exception's nur in High-Level Funktionen benutzen, die die Programflußebene darstellen die durch die
GUI Events aufgerufen werden.
Exceptions in Lowlevel Funktionen, wie zB. StrToInt() sind im Grunde eher störend und sollten generell vermieden werden. Im Falle von StrToInt() könnte man argumentieren das es die Highlevel Schnittstelle zu TryStrToInt() oder StrToIntDef() darstellt. Dies ist insofern richtig wenn man StrToInt() innerhalb von
GUI Events betrachtet. Da StrToInt() aber eine Funktion der
RTL ist würde ich eher meinen das es eine LowLevel Funktion darstellt und eigentlich KEINE
Exception auslösen sollte.
Exceptions NIEMALS in Release-Funktionen benutzen. Sprich Funktionen die Objecte oder Daten freigeben sollten keine Exceptions auslössen. Dies liegt daran das solche Funktionen meistens gruppiert in übergeordenten Funktionen auftreten. Würde eine
Exception ausgelösst so bedeutete dies das nachfolgende Release-Funtionen Speicherleaks produzieren würden. Technologisch müsste der anwendende Coder nun JEDEN Aufruf solcher Release-Funktionen per separatem try finally schützen. Es ensteht eine Sinnlosigkeit der Exceptions in diesem Falle.
Exception dagegen in Allocator-Funktionen, sprich Constructoren, verwenden. Die Exceptions verhindern somit die weitere Allokation von sinnlosen Speicherbereichen.
Code immer schützen mit try finally end Blöcken, egal ob mit oder ohne Exceptions gearbeitet wird.
try finally Blöcke werden IMMER ausgeführt wenn sie als ÄUSSERTER Block verwendet werden. Demzufolge sollten try finally Blöcke zu-äusserst stehen
In fast allen Fällen reicht EIN einzigster try finally Block pro Funktion aus. Zb. so
Delphi-Quellcode:
var
S,D: TStream;
begin
S := nil;
D := nil;
try
S := TFileStream.Create(...);
D := TFileStream.Create(...);
.....
finally
S.Free;
D.Free;
end;
end;
Hier sieht man das man immer mit einem try finally auskommen kann.
try except Blöcke immer mit bedacht und sparsam einsetzen. Ein vollständiges Abklemmen aller Exceptions per try except Block ist fast immer schlecht aus Sicht der Wartung des Programmes.
Exceptions sollten nach Möglichkeit nur zur Fehlerbehandlung benutzt werden, AUCH wenn man reine Ausnahmebedinungen damit realisieren könnte. Diese Regel dient zur Vorbeugung von Mißverständnissen durch andere Programmierer. Bestes Beispiel ist die häufigste Frage von
INDY Anwendern, was "Connection closed gracefully" denn für ein Fehler ist ?!
Exceptions sind also KEIN Ersatz für Funktionen und deren Rückgabe-Werte. Exceptions sind hier vergleichbar mit der Möglichkeit ALLES Objectorientiert und basierend auf Kompoenenten zu codieren, auch wenn eine kleine Funktion ausreichen würde. Auch die
OOP und Komponenten sind KEIN Ersatz der prozeduralen Programmierung.
Das hinterhältige an Exceptions ist deren Fähigkeit das Black-Box-Prinzip der prozeduralen Programmierung zu zerstören !!
Exceptions also NUR auslösen wenn eine Bedingung eintritt in der der Programfluß KEINESFALLS fortsetzbar ist.
Gruß Hagen