Home » Object Pascal » Exceptions

Exceptions

Bei einer objektorientierten Programmiersprache dürfen Exceptions nicht fehlen. Exceptions werden ausgelöst, wenn ein Fehler auftritt. Wird die Stelle im Code von try…except oder try…finally umgeben, so wird die Programmausführung an der Stelle abgebrochen, an der der Fehler aufgetreten ist, und im except- bzw. finally-Abschnitt fortgesetzt. Exceptions sind Klassen, die Exception als gemeinsame Basisklasse haben. Im Code, der im Fehlerfall ausgeführt wird, kann geprüft werden, was für eine Exception ausgelöst wurde.

Es ist auch möglich, eigene Exceptions zu erstellen und auszulösen. Die Namen von Exceptions beginnen dem Styleguide zufolge mit einem großen E.

type
 EMyError = class(Exception);

Exception auslösen:

raise EMyError.Create;

Fehler werden mit try…except oder try…finally abgefangen. Der exception-Abschnitt wird nur im Fehlerfall durchlaufen, der finally-Abschnitt auf jeden Fall.

try
 ...
except
 ...
end;

Im except-Abschnitt lässt sich prüfen, was für eine Exception aufgetreten ist:

except
 on EZeroDivide do ...;
 on EMathError do ...;
 on EMyError do ...;
else
 ...;
end;

Der else-Abschnitt wird immer dann ausgeführt, wenn die aufgetretene Exception nicht davor behandelt wurde.
Detailliertere Informationen zu Exceptions finden Sie in unserem Tutorial.

Die Einführung von Exceptions revolutionierte die gesamte Fehlerbehandlung. Sie sind sehr effektiv, wenn es um das Abfangen von Fehlern, den sog. Exceptions, geht. Jedoch ist vielen nicht bewusst, dass Exception-Blöcke auch das Programmieren mit angezogener Handbremse bedeuten können. Das Verwalten eines try/finally bzw. try/except verschlingt auch Rechenzeit. Ein Exception-Block sollte deswegen nicht in einer Schleife stehen, die mehrere tausend Mal durchlaufen wird. Die Exception-Blöcke sollten an strategisch wichtigen Punkten platziert werden anstatt wild im Programm verstreut zu sein. Der ungeeignetste Platz für einen Exception-Block ist, wie bereits gesagt, der in einer Schleife. Dort wird der Exception-Block mehrmals durchlaufen und raubt bei jedem Durchlauf die Rechenzeit, die zwar relativ gering ist, aber in einer Schleife mit der Anzahl der Durchläufe multipliziert wird. Um einen Exception-Block aus so einer Schleife zu entfernen, gibt es zwei Möglichkeiten. Die erste funktioniert nur, wenn es egal ist, ob die gesamte Schleife beim Auftritt der Exception abgebrochen wird, was aber sicherlich nicht zutreffen sollte, da man ansonsten den Exception-Block von Anfang an bereits außerhalb der Schleife betreten hätte.
Die zweite Lösung ist etwas komplizierter, aber dafür schneller. Hier wird eine weitere Funktion aufgerufen, die auch lokal sein kann und der ein StartIndex für die Schleife übergeben wird. Nun wird die gesamte Schleife in diese Funktion ausgelagert, wobei sie vom StartIndex ab anfängt zu zählen und in einen try/except-Block gesteckt wird. Diesem StartIndex weist man in der Schleife nun die Zählvariable zu (nur bei for-Schleife nötig, bei while/repeat until nutzt man StartIndex einfach als Zählvariable). Im except-Block führt man nun seine Behandlung durch und setzt eine lokale Variable ExceptionRaised auf True. Hinter dem except-Abschnitt wird dann die Funktion in Abhängigkeit von ExceptionRaised mit dem StartIndex + 1 aufgerufen.
Alternativ kann man für bestimmte Operationen auf die Exception-Auslösung ganz verzichten. So bietet Delphi neben den StrToXxx Funktionen auch noch TryStrToXxx und StrToXxxDef Funktionen an. Außerdem gibt es noch die sehr mächtige Funktion Val(), die von den meisten StrToXxx Funktionen aufgerufen wird.

procedure TMyClass.DoSomething;
var i: Integer;
begin
 for i := 0 to High(FMyField) do
 begin
   try
     FMyField[i].DoIt;
   except
     ShowMessage('Invalid: ' +
     IntToStr(i));
   end;
 end;
end;
procedure TMyClass.DoSomethingIntern(
 StartIndex: Integer);
var  ExceptionRaised: Boolean;
begin
  ExceptionRaised := False;
  try
    for i := StartIndex to High(FMyField) do
    begin
      StartIndex := i;
      FMyField[i].DoIt;
    end;
  except
    ExceptionRaised := True;
    ShowMessage('Invalid: ' + IntToStr(i));
  end;
  if ExceptionRaised then
    DoSomethingIntern(StartIndex + 1);
end;

procedure TMyClass.DoSomething;
begin
 DoSomethingIntern(0);
end;