Иерархия классов исключений

Обработка исключительных ситуаций.

Основные вопросы лекции:

  1. Понятие исключительной ситуации и пути их возникновения
  2. Обработка исключительных ситуаций оператором IF-THEN-ELSE
  3. Обработка с использованием блока TRY-EXCEPT-END
  4. Иерархия классов исключений
  5. Обработка с использованием блока TRY-FINALLY-END

Понятие исключительной ситуации

Исключительная ситуация (исключение) – некоторая ситуация в программе, которая требует специальной обработки.

Например: при делении двух чисел произошло деление на 0. Если такую ситуацию не обработать, то возникает системная ошибка и программа прекращает свою работу.

Очевидно, что практически каждая операция может вызывать исключительную ситуацию: деление на 0, извлечение корня четной степени из отрицательного числа, ошибка преобразования типа, чтение данных из неоткрытого (несуществующего) файла, …

Для обработки таких ситуаций можно использовать разные подходы.

Обработка исключительных ситуаций оператором IF-THEN-ELSE

Способ хорош тем, что конструкция общеизвестна и не требует дополнительных пояснений. Например, для того, чтобы избежать ошибки деления на 0 нужно записать:

IF B<>0 THEN C:=A/B ELSE ShowMessage(‘Ошибка при делении на 0’);

Существенным недостатком данного способа является применимость его только к одному потенциально опасному оператору (в противном случае приходится строить достаточно сложные логические условия), а также громоздкость записи. Например, для исключения ошибки извлечения корня из отрицательного числа следует все подкоренное выражение записать в условии с проверкой на положительное значение, кроме того само подкоренное выражение может содержать потенциальные ошибки (деление на 0, корень из отрицательного числа и т.д.). В силу перечисленных обстоятельств данный способ обработки исключений находит весьма ограниченное применение.

Обработка с использованием блока TRY-EXCEPT-END

В среде Delphi имеются специальные блоки обработки исключений. Рассмотрим первый из них:

Синтаксис:

Try

<фрагмент программы>

Except

On <класс исключения> Do <обработка исключения>;

Else

<обработка исключения>

End;

Правило действия:

  1. Выполняется набор оператор, заключенных между Try и Except.
  2. Если некоторый оператор в защищенном блоке вызвал ошибку, то прекращается выполнение остальных операторов блока и управление передается в блок Except-End.
  3. В блоке Except-End среди операторов обработки ищется первый способный обработать возникшую ошибку. Если такой обработчик найден, то он выполняется и управление передается оператору, следующему за End, в противном случае выполняется обработчик записанный после слова Else.
  4. Если в защищенном блоке не произошло ошибок, то управление передается на оператор, следующий за End, закрывающим блок обработки исключений.

Пример:

a:=5;b:=0;d:=5; try d:=a/b; b:=2; except on EZeroDivide do d:=0; end; Label1.Caption:=FloatToStr(d)+' '+FloatToStr(b);

В компонент Label1 будет выведено «0 0», т.е. после деления на 0 оператор b:=2; выполнен не будет.

Особенности работы блока Try-Except:

1. Если секция Except-End не содержит ни одной конструкции On Do и Else, а только серию операторов, то считается что данная серия операторов обрабатывает любое исключение.

2. Если блок обработки исключения является пустым, то стандартное сообщение об ошибке не выдается, программа продолжает свою работу, но оценить достоверность результата невозможно.

Так если в рассмотренном примере убрать строку on EZeroDivide do d:=0;, то программа продолжит работу не выдав никаких сообщений, но значение переменной d так и останется равным 5.

3. Допустима произвольная вложенность блоков друг в друга.

Иерархия классов исключений

Классы исключений построены по иерархическому принципу. Если более общий класс, но встречающийся в блоке Except-End раньше более узкого класса может обработать возникшее исключение, то он это сделает и очередь до нужного обработчика так и не дойдет.

Например, располагать обработчики в таком порядке абсолютно бессмысленно, т.к. сработает первый из них:

on EIntError do …; on ERangeError do …; on EDivByZero do …;

Целесообразно было бы записать так:

on ERangeError do …; on EDivByZero do …; on EIntError do …;

Таблица классов исключений

Родитель1 Родитель2 Класс Обрабатываемое исключение
Exception EAbort   Обработка любого исключения
  EArrayError   Возникает при различного рода ошибках при работе с массивами.
  EConvertError   Ошибка преобразования в функциях StrToInt или StrToFloat
  EInOutError   Любая ошибка в файловых операциях. Поле ErrorCode объекта этого класса содержит код ошибки.
  EInvalidGrid Operation   Программа пытается выполнить недопустимую операцию над таблицами (обращение к несуществующему столбцу и т.д.).
  EStackOverflow   Исчерпан объем выделенного программе стека.
Целочисленные операции
  EIntError   Любая ошибка в целочисленных выражениях
    EDivByZero Ошибка целочисленного деления на 0
    EIntOverflow Ошибка целочисленного переполнения, когда целочисленной переменной присваивается значение, выходящее за пределы 32 двоичных разрядов.
    ERangeError Целочисленный результат превышает емкость целого типа данных
Операции с вещественными числами
  EMathError   Любая ошибка при выполнении вычислений с плавающей точкой.
    EInvalidArgument Возбуждается математическими функциями при выходе аргумента за пределы допустимого диапазона.
    EOverflow Переполнение в операциях с плавающей точкой
    EUnderflow Результат операции с плавающей точкой слишком мал, чтобы уместиться в регистрах сопроцессора.
    EZeroDivide Вещественное деление на 0.

Для обработки результатов работы с файлами следует использовать обработчик:

try Reset(f); while not(eof(f)) do begin … end; CloseFile(f); except on E: EInOutError do ShowMessage(‘При выполнении файловой операции возникла ошибка № ’+IntToStr(E.ErrorCode) ); end;

Наши рекомендации