Exception-Handling


Abstract

Thema dieses Artikles ist der sinnvolle Einsatz von Exceptions - wie Exceptions nicht eingesetzt werden sollten und wie stattdessen richtig eingesetzt werden. Als Vorlage bzw. Quelle zu diesen Artikel diente mir der Artikel von Nick Hodges "Exception Handling for fun and Profit" [1]. Siehe dazu auch die Diskussion in der Delphi-Praxis [2]: try ... except --> wann verwenden ??? [3].

Einleitung

Exceptions werden von dem Betriebssystem bereitgestellt, um es den Programmierer zu erlauben den Programm ablauf an einer Stelle sofort zu unterberchen. Desweiteren muss diese Art der Ausnahmebehandlung (Exception-Handling) auch vo der Sprache unterstützt werden und natürlich auch vom Programmierer eingesetzt werden im Code-Design. Der Sinn von Exceptions ist es das Auftreten von nicht beeinflussbaren Ereignissen oder Randbedingungen abzufangen, die man entweder nicht beeinflussen kann oder die eine Ausnahme bilden und zu Fehlern im weiteren Programmablauf führen. Das heißt, man muss Annahmen treffen und entsprechend, mit der Hilfe von Exceptions, reagieren, wenn diese nicht zutreffen.

Werden Exceptions richtig eingesetzt, könnnen sie helfen guten, sauberen Code zu schreiben, der auch in Zukunft gut zu warten ist. Im Gegensatz dazu kann der falsche Gebrauch von Exceptions letztendlich mehr Fehler und Probleme verursachen, als er vermeiden sollte.

Wie man Exceptions nicht verwenden sollte ...

Don't eat exceptions!

Don't eat exceptions.

So hat es Nick Hodges in seinem Artikel bezeichnet, wenn Exceptions im exception-Block einfach ignoriert werden, was tunlichst man nicht tun sollte.

Beispiel:

try
  SomeCodeThatMightCauseAnAccessViolation;
except
  // do nothing
end;

In diesem Code wird einfache jede mögliche auftretende Exception ignoriert / verworfen oder um es mit Nick Hodges Worten zu sagen: "gefressen". Für diese Art der Fehlerbehandlung gibt es meist zwei Gründe. Zum einem will der Entwickler entweder dem Benutzer keine Fehlermeldung zeigen oder aber einfach nur den Fehler ignorieren. Sollte er ersters bezwecken, wäre es trotzdem sinnvoll die Excpetion irgendwie aufzuzeichnen zur späteren Fehler suche.

Nichts desto trotz ist es sehr gefährlich Exceptions generell einfach zu verschlucken. Denn das bedeutet, dass das Programm eventuell falsche Ergebnisse liefert, aber es trotzdem so aussieht, als ob alles in bester Ordnung wäre. Und je nach dem, was das Programm macht, kann dies fatale Folgen haben.

Generell alle Ausnahmen abfangen

try
  SomeCode;
except
  on E: Exception do
  begin
    ShowMessage(E.Message);
  end;
end;

Auch das generelle Abfangen von allen Ausnahmen ist nicht zu empfehlen. Denn was tut der obige Code eigentlich? Er reeagiert auf jede Exception und zu dem erstickt er die Exception im Keim. Wird eine Exception lokal behandelt, hat sie keine Möglichkeit nach aussen sichtbar zu werden. Wird dieser Code dann in einer Klasse ausgeführt, hat derjenige, der die Klasse benutzt, keine Möglichkeit auf die Exception zu reagieren.

Benutze Exceptions nicht zur Überprüfung von Code

Exceptions bedeuten für die CPU und das Betriebssystem eine recht hohen Verwaltungsaufwand. Aus diesem Grund sollte man sie gezielt und mit Bedacht einsetzen und auch nur für den Zweck, für den sie eigentlich betsimmt sind.

Sehr häufig sieht man zum Beispiel in Foren folgenden - oder ähnlichen - Code:

function StringIsInteger(aStr: string): Boolean;
var
  Temp: integer;
begin
  Result := True;
  try
    Temp := StrToInt(aStr);
  except
    Result := False;
  end;
end;

Nun, er macht genau das was er solll. True zurückgeben, wenn es die Zeichenfolge in einen Integer konvertiert werden kann und False, wenn dies nicht der Fall. Nur ist der Fehlerfall nicht unbedingt die Ausnahme, sondenr es wird mit ihm gerechnet. Wird diese Funktion häufig aufgerufen, kann dies zu erheblichen Performance-Einbusen führen.

... und wie man es richtig macht

Die strukturierte Ausnahmebehandlung ist eine Möglichkeit die Fehlerbehandlung im Code von der Programmabluaflogik zu trenne. Man kann also seinen Code schreiben und praktisch so tun, als ob nie ein Fehler auftreten könnte, um dann diesen Code mit einem try-except-Block zu umschliessen und dort letztendlich die Fehlerbehandlung durchzuführen. Damit kann man effizienteren Code schreiben, da eine ständige Überprüfung der Daten und Parameter wegfällt.

Anwender sollten Ausnahmen abfangen und Entwickler sollten Ausnahmen werfen

Es gibt immer zwei Beteiligte, den einen, der Code entwicklt und schreibt und den anderen, der diesen Code in seiner Anwendung benutzt. Natürlich können in der Praxis beide beteiligten in einer Person vereint sein. Im ideal Fall sollten der Entwickler der Bibliothek, Klasse oder Komponente die Exceptions erzeugen bzw. werfen. Der Anwender/Benutzers dieses Quellcodes sollte dann nur noch die Exceptions entsprechend behandeln.

Wirf eigene passende Exceptions

wenn man selber Exceptions wirft, sollte man seine eigenen an den Code angepasste Exceptions werfen. Zum einem kann dann der Anwender des Codes explizit die Exceptions abfangen, die ihn interessieren und man kann auch erkennen, von wo sie kommen, also wer oder was sie geworfen hat. Seine eigenen Exceptions kann man einfach von der Exception Klasse ableiten un dbei Bedarf natürlich noch für sich erweitern und anpassen.

Gib sinnvolle Exceptiontexte aus

Es ist auch immer sehr hilfreich, wenn man einen Text ausgibt, mit dem man dann im Fall der Fälle auch etwas anfangen kann. Die VCL ist da ein gutes schlechtes Beispiel. "Listindex out of bounds" ist da ein schönes Beispiel. Es wird weder die Klasse noch sonst eine weiter Information ausgegeben, die bei der Fehlersuche helfen könnte. Man könnte zum Beispiel den Prozedurnamen oder sonst irgendwelche hilfreichen Informationen mit ausgeben.

Fazit

Exceptions sind also dann sinnvoll, wenn durch eine (äußere) Bedingung, auf die man keinen Einfluss hat, der weiter korrekte Programmablauf nicht mehr sicher gestellt ist. Solche Situationen können zum Beispiel auftreten, wenn eine Verbindung zu einer Datenbank unterbrochen wird während eine Abfrage oder Transaktion, denn darauf hat man meist keinen Einfluss. Allerdings führt so etwas zu einem Fehler in der Anwendung nach dessen Auftreten ein weiterer korrekter Programmablauf nicht mehr gegeben ist.

Links

[1] http://bdn1.borland.com/borcon2004/article/paper/0,1963,32156,00.html
[2] http://www.delphipraxis.net
[3] http://www.delphipraxis.net/topic115413,0,asc,0.html


2010-12-29T23:44:45 +0100, mail+homepage[at]michael-puff.de