Blok Try...Except


Wyjątki są obsługiwane w obrębie instrukcji try...except. Przykład:

try
  X := Y/Z;
except
  on EZeroDivide do HandleZeroDivide;
end;

Instrukcja ta próbuje podzielić Y przez Z, ale w razie zgłoszenia wyjątku EZeroDivide wywołuje procedurę o nazwie HandleZeroDivide.

Formalna składnia instrukcji try...except:

try 
 statements
except 
 exceptionBlock 
end

gdzie statements są sekwencją instrukcji (oddzielanych średnikami) zaś blok wyjątku (exceptionBlock, czyli instrukcje w bloku except...end) jest albo:

else statements

Procedura obsługi wyjątku (exception handler) posiada następującą składnię:

on identifier: type do statement

gdzie identifier jest opcjonalny, type jest identyfikatorem typu wyjątku, natomiast statement jest dowolną instrukcją.

Instrukcja try...except wykonuje instrukcje z inicjującej listy instrukcji (między try i except). Jeśli nie zostanie zgłoszony żaden wyjątek, blok wyjątku (exceptionBlock) jest ignorowany sterowanie wykonaniem programu przekazywane jest do następnych instrukcji.

Jeśli podczas wykonania listy inicjujących instrukcji zgłoszony zostanie wyjatek, czy to poprzez instrukcję raise w liście instrukcji, czy też poprzez procedurę lub funkcję wywołaną z listy instrukcji, dokonywana jest próba obsłużenia wyjątku.

Kiedy żaden z powyższych warunków nie jest spełniony, poszukiwanie kontynuowane jest w bloku wyjątku bezpośrednio nadrzędnej instrukcji try...except, takiej która przejęła sterowanie "najbardziej ostatnio" i jeszcze go nie przekazała (chodzi o instrukcję try..except, w której zagnieżdżono bieżącą instrukcję try..except). Jeśli nie zostanie tam znaleziony odpowiedni handler, klauzula else, ani lista instrukcji, poszukiwanie przenoszone jest do następnej z kolei nadrzędnej instrukcji try...except itd. Jeśli zostanie przeszukana najbardziej zewnętrzna instrukcja try...except, a wyjątek nadal będzie nieobsłużony, program jest przerywany.

Kiedy wyjątek jest obsłużony, stos jest przeszukiwany do tyłu, aż do procedury lub funkcji zawierającej instrukcję try...except, gdzie przeprowadzana jest obsługa i sterowanie jest przekazywane do wykonywanej procedury obsługi wyjątku, klauzuli else, lub listy instrukcji. Ten proces odrzuca wszystkie wywołania procedur i funkcji, które mają miejsce po wejściu sterowania do instrukcji try...except, w której odbywa się obsługa wyjątku. Obiekt wyjątku jest potem automatycznie niszczony poprzez wywołanie jego destruktora Destroy i sterowanie jest przekazywane do instrukcji następujących po try...except. (Jeśli wykonane zostanie wywołanie procedury standardowej Exit, Break, lub Continue sterowanie przekazywane jest poza procedurę obsługi wyjątku, a obiekt wyjątku jest niszczony.)

W poniższym przykładzie, pierwszy handler obsługuje wyjątek generowany na skutek dzielenia przez zero, drugi obsługuje wyjątki generowane na skutek przepełnienia (overflow), a ostatni obsługuje wszystkie inne wyjątki. EMathError zamieszczony jest na końcu, ponieważ jest on przodkiem pozostałych dwóch klas wyjątków; jeśli byłby umieszczony jako pierwszy, pozostałe handlery nigdy nie byłyby wykorzystane.

try
 ...
except
  on EZeroDivide do HandleZeroDivide;
  on EOverflow do HandleOverflow;
  on EMathError do HandleMathError;
end;

Procedura obsługi wyjątku może specyfikować identyfikator przed nazwą klasy wyjątku. Stanowi to deklarację zmiennej do reprezentacji obiektu wyjątku podczas wykonywania instrukcji umieszczonych w klauzuli on...do. Zakres ważności identyfikatora jest ograniczony do tych instrukcji. Przykład:

try
 ...
except
  on E: Exception do ErrorDialog(E.Message, E.HelpContext);
end;

Jeśli w bloku wyjątku wyspecyfikowano klauzulę else, obsługuje ona pozostałe wyjątki nie obsłużone wcześniej. Przykład:

try
 ...
except
  on EZeroDivide do HandleZeroDivide;
  on EOverflow do HandleOverflow;
  on EMathError do HandleMathError;
else
  HandleAllOthers;
end;

Tutaj, klauzula else obsługuje wyjątki inne niż EMathError.

Blok wyjątku nie zawierający żadnych procedur obsługi wyjątków, składający się tylko z listy instrukcji, obsługuje wszystkie wyjątki. Przykład:

try
 ...
except
  HandleException;
end;

Tutaj, procedura HandleException obsługuje dowolny wyjątek, jaki zdarzy się w efekcie wykonania instrukcji między try i except.