Класс Exception - обработка исключений

Виды ошибок. В процессе разработки и выполнения программ возникают следующие виды ошибок:

· Синтаксические.Вызываются нарушением синтаксиса языка и выявляются и устраняются при компиляции программы, т.е. компилятор выдает сообщение и показывает в тексте программы место, где возникла ошибка.

· Логические.Это следствие реализации неправильного алгоритма и проявляются при выполнении программы. Наличие таких ошибок не приводит к выдаче пользователю сообщений или прекращению работы программы, но программа будет работать неправильно.

· Динамические.Возникают при выполнении программы и являются следствием неправильной работы инструкций, процедур, функций, а также операционной системы. Такие ошибки называются ошибками времени выполнения. Например, при делении на переменную, которая в процессе выполнения программы могла получить нулевое значение.

Исключения генерируются компонентами Delphi для различных событий, таких как присвоение свойству значения, выходящего за допустимые пределы, или попытка индексировать несуществующий элемент массива. Исключительная ситуация возникает при выполнении некорректной математической операции, такой как деление на ноль. Потенциально любой оператор программы может стать причиной исключительной ситуации. Однако некоторые операторы относительно безопасны, и задача при написании устойчивой программы состоит в основном в том, чтобы правильно решить, для каких операторов нужна защита, а какие безопасны.

Ниже приведены некоторые типы операций, которые могут привести к исключительным ситуациям:

· обработка файла;

· выделение памяти;

· работа с ресурсами системы;

· работа с объектами и формами, создаваемыми во время выполнения программы;

· аппаратные конфликты и конфликты операционных систем.

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

Генерация исключения означает всего лишь то, что приложение создало объект исключения и максимально подробно описало ошибку. Если мы не обрабатываем исключение (т.е. не приготовлен специальный код для перехвата исключения), приложение само сделает это автоматически. Обычно приложение обрабатывает исключение, выводя на экран монитора окно с сообщением о возникшей ошибке.

Рассмотрим следующий пример. В поля Edit1 и Edit2 записываются вещественные числа. При щелчке по кнопке Button1 выполняется перевод введенных строк в числовой формат, первое число делится на второе и результат выводится в Edit3.

procedure TForm1.Button1Click(Sender: TObject);

Var a,b,c:real;

Begin

a:=StrToInt(Edit1.Text);

b:=StrToInt(Edit2.Text);

c:=a/b;

Edit3.Text:=FloatToStr(c);

End;

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

Защищенные блоки. Чтобы обработать исключение, сгенерированное функцией StrToInt или оператором присваивания c:=a/b, надо поместить эти операторы в защищенный блок кода. Защищенным является блок кода, который может реагировать на некоторое исключение. В Delphi защищенный блок выглядит следующим образом:

Try

{Операторы, выполнение которых может вызвать ошибку}

Except

{Операторы, которые должны быть выполнены в случае ошибки}

End;

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

Введем для рассмотренного выше примера локальную обработку исключительных ситуаций. Для этого сформируем защищенный блок без анализа ошибок.

procedure TForm1.Button1Click(Sender: TObject);

Var a,b,c:real;

Begin

Try

a:=StrToInt(Edit1.Text);

b:=StrToInt(Edit2.Text);

c:=a/b;

Edit3.Text:=FloatToStr(c);

Except

ShowMessage('Ошибка!');

End;

End;

В этом случае при возникновении любого исключения будет прерываться выполнение операторов защищенного блока, в Edit3 результат не появится. На экран будет выведено окно с сообщением «Ошибка!». Операторы, расположенные после защищенного блока, будут выполняться.

Секция Except может быть разбита на несколько частей On...Do для обработки разных классов исключений. После конструкций On...Do может быть помещен раздел Else, который относится ко всему блоку. По логике работы группа конструкций On...Do напоминает оператор Case. К исключениям, не имеющим своих локальных обработчиков, применяется механизм глобальной обработки через объект Application.

Try

{Операторы, выполнение которых может вызвать ошибку}

Except

{Операторы, которые должны быть выполнены в случае ошибки}

On Исключение Do Его_Обра6отка;

On Другое_Исключение Do Его_Обработка;

Else Обработка_Всех_Остальных_Исключений;.

End;

Поиск нужного обработчика осуществляется с начала списка вниз до тех пор, пока не встретится класс, способный обрабатывать исключение данного типа. Если подходящего класса не обнаружено, управление передается операторам, стоящим за словом Else, а если таковых нет (часть Else <операторы> может опускаться), выполняется умалчиваемая обработка исключения.

Стандартные классы исключений. Механизмы обработки ошибок в Delphi инкапсулированы в класс Exception – базовый класс. Потомки этого класса охватывают большое количество исключений, которые могут возникнуть в процессе работы приложений. Имена потомков класса Exception начинаются с буквы E. В табл. 20 приведены наиболее часто используемые классы исключений.

Таблица 20

Класс Родитель Обрабатываемое исключение
EAbort Exception Реализует «тихую» (без какого-либо сообщения) обработку любого исключения
EArrayError Exception Возникает из-за различного рода ошибок при работе с массивами (неверный индекс, попытка вставить элемент в массив фиксированной длины или в отсортированный массив и т. п.)
EConvertError Exception Ошибка преобразования в функциях StrToint или StrToFloat
EDivByZero EIntError Ошибка целочисленного деления на ноль
EFCreateError EStreamError Ошибка при создании файла. Например, попытка создать файл на устройстве, предназначенном только для чтения, или в несуществующем каталоге
EInOutError Exception Любая ошибка в файловых операциях. Поле ErrorCode объекта этого класса содержит код ошибки
EIntError Exception Любая ошибка в целочисленных вычислениях
EIntOverflow EIntError Ошибка целочисленного переполнения: программа пытается присвоить целочисленной переменной значение, выходящее из 32-двоичных разрядов
EInva1idArgument EMathError Возбуждается математическими функциями при выходе аргумента из допустимого диапазона
EInvalidGraphic-Operation Exception Программа пытается выполнить недопустимую графическую операцию
EInvalidGrid-Operation Exception Программа пытается выполнить недопустимую операцию над таблицей (например, обратиться к несуществующему столбцу или ряду)
EInvalidOp EMathError Ошибка в операциях с плавающей точкой (недопустимая инструкция, переполнение стека сопроцессора и т. п.)
EMathError Exception Любая ошибка при выполнении вычислений с плавающей точкой.
EOutOfMemory EHeapException Эта ошибка возникает, когда программа запрашивает слишком большой для данной конфигурации Windows объем памяти
EOverflow EMathError Результат операций с плавающей точкой слишком велик, чтобы уместиться в регистрах сопроцессора
EPropertyConvert Error Exception Ошибка при чтении или записи значения свойства
EPropertyError Exception Ошибка доступа к свойству при чтении или записи
ERangeError EIntError Целочисленный результат превышает емкость целого типа данных
EZeroDivide EMathError Вещественное деление на ноль

Важно помнить, что ищется самый первый из, возможно, нескольких обработчиков, класс которого способен обрабатывать данное исключение. Если, например, в списке первым стоит EAbort, который может обработать любое исключение, ни один из стоящих за ним обработчиков никогда не получит управления. Точно так же, если указан обработчик для класса EintError, за ним бесполезно размещать обработчики EDivByZero, ERangeError или EIntOverflow:

Try

Except

// Не имеет смысла делать так:

On EIntError do .....;

On ERangeError do .....;

On EDivByZero do .....;

// Надо так:

On ERangeError do .....;

On EDivByZero do .....;

On EIntError do .....;

End;

Изменим секцию Except в рассмотренном выше примере.

Try

a:=StrToFLoat(Edit1.Text);

b:=StrToFloat(Edit2.Text);

c:=a/b;

Edit3.Text:=FloatToStr( c);

Except

On EConvertError Do ShowMessage('Ошибка преобразования! ');

On EZeroDivide Do

Begin ShowMessage('Попытка деления на ноль!'); Edit2.SetFocus End;

On EInvalidOp Do ShowMessage(' Ошибка 0/0');

End;

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

Слово Raise возбуждает исключение самого общего класса Exception. Если программист желает возбудить исключение конкретного типа (не важно - стандартного или собственного), он должен явно указать класс создаваемого в этот момент объекта путем вызова его конструктора. Например, следующий оператор возбудит ошибку ввода/вывода:

Raise EInOutError.Create('Ощибка!') ;

Такой прием - единственная возможность возбудить нестандартное исключение, обрабатываемое пользовательским классом.

Создание собственного класса. Программист может создать собственный класс обработки исключений, объявив его потомком Exception или любого другого стандартного класса (этим другим чаще всего бывает класс EAbort). Объявление нестандартного класса имеет смысл только тогда, когда вам необходимо научить программу распознавать некорректные наборы данных и соответствующим образом на них реагировать.

Пусть, например, в программе примера, рассмотренного выше, необходимо провести контроль неотрицательности полученного результата (переменной с), поскольку в дальнейшем эта переменная является, допустим, аргументом функций вычисления логарифма или квадратного корня.

Создадим новый класс ECheckError и будем возбуждать исключение этого класса при обнаружении ошибки в данных:

var

Form1: TForm1;

Type

ECheckError = Class(EAbort)

end;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);

Var a,b,c:real;

Begin

Try

a:=StrToFLoat(Edit1.Text);

b:=StrToFloat(Edit2.Text);

c:=a/b;

Edit3.Text:=FloatToStr( c);

If c < 0 then

Raise ECheckError.Create('Отрицательное число');

Except

On E: ECheckError Do ShowMessage(E.Message) ;

On EConvertError Do ShowMessage('Ошибка преобразования! ');

On EZeroDivide Do

Begin ShowMessage('Попытка деления на ноль!'); Edit2.SetFocus End;

On EInvalidOp Do ShowMessage(' Ошибка 0/0');

End;

В этом примере создается класс ECheckError, который ничем, кроме названия, не отличается от своего родителя EAbort. В реальной программе потомок обычно расширяет набор полей (свойств) своего родителя или перекрывает его методы; приведенный пример лишь иллюстрирует, что делать это необязательно. При неудачной проверке оператором

Raise ECheckError.Create('Отрицательное число') ;

возбуждается исключение нового класса. При этом с помощью унаследованного конструктора Create создается новый безымянный объект, а строковый параметр обращения к конструктору запоминается в поле FMessage и становится доступен с помощью свойства Message объекта. Обработчик исключения ECheckError именует объект идентификатором E и с помощью стандартной процедуры ShowMessage показывает его в небольшом окне на экране.

Пример наглядно показывает выгоды использования исключений. В принципе весь этот фрагмент можно было бы написать с проверками If... Then, но в этом случае логика программы была бы более запутанной, а сама программа более сложной в отладке.

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

Try

...{Операторы, выполнение которых может вызвать ошибку}

Finally

{Операторы, которые должны быть выполнены в любом случае}

End;

Данная конструкция применяется для выполнения всех необходимых действий перед передачей управления на следующий уровень обработки ошибки или глобальному обработчику. Такими действиями могут быть, например, освобождение оперативной памяти или закрытие файла. Эта конструкция не обрабатывает объект-исключение и не удаляет его, а выполняет действия, которые должны быть произведены даже в случае возникновения ошибки. Конструкция работает следующим образом: если в любой из инструкций блока Try возникает исключение, то управление передается первой инструкции блока Finally. Если же исключение не возникло, то последовательно выполняются все инструкции обоих блоков. На рис. 23 представлена логика работы оператора Try…Finally…End.

Класс Exception - обработка исключений - student2.ru

Рис. 23

Конструкцию Try...Finally можно включить в блок Try...Except. Это позволяет выполнить обязательные операторы секции Finally и обработать исключение операторами секции Except. Оба типа конструкций можно использовать в любом месте, допускается вложенность любой глубины (рис. 24 а, б).

Настройка Delphi – отключение реагирования на исключительные ситуации.При работе программы под управлением Delphi, система будет сама реагировать на исключительные ситуации, мешая работе операторов обработки исключений. Чтобы проверить их действие, можно запускать программу непосредственно из папки (exe-файл или можно отключить реакцию системы на исключительные ситуации, тем самым давая возможность отработать специально для этого написанным фрагментам программы - операторам Try … Except … End.Для этого надо вызвать опцию Tools ® Options ® Debugger Options ® Language Exceptions и снять флажок Notify on Language Exceptions.Теперь система Delphi будет предоставлять программе возможность самостоятельно обрабатывать исключительные ситуации, среди которых могут быть и ситуации, возникновение которых прописано специально как удобный инструмент достижения необходимых результатов.

Класс Exception - обработка исключений - student2.ru

Рис. 24

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