Exceptions
are handled within try...except statements. For example,
try
X := Y/Z;
except
on EZeroDivide do
HandleZeroDivide;
end;
This
statement attempts to divide Y by Z, but calls a routine named HandleZeroDivide
if an EZeroDivide exception is raised.
The
syntax of a try...except statement is
try statements except exceptionBlock end
where statements is a sequence of
statements (delimited by semicolons) and exceptionBlock is either
·another sequence of statements or
·a sequence of exception handlers, optionally
followed by
else statements
An
exception handler has the form
on identifier: type do statement
where identifier: is optional (if
included, identifier can be any valid identifier), type is a type
used to represent exceptions, and statement is any statement.
A try...except
statement executes the statements in the initial statements list. If no
exceptions are raised, the exception block (exceptionBlock) is ignored
and control passes to the next part of the program.
If an exception is raised during execution of the initial statements list, either by a raise statement in the statements list or by a procedure or function called from the statements list, an attempt is made to handle the exception:
· If any of the handlers in the
exception block matches the exception, control passes to the first such
handler. An exception handler matches an exception just in case the type
in the handler is the class of the exception or an ancestor of that class.
· If no such handler is found, control passes to the statement
in the else clause, if there is one.
· If the exception block is just a sequence of statements without any
exception handlers, control passes to the first statement in the list.
If none of the conditions above is satisfied, the search continues in the exception block of the next-most-recently entered try...except statement that has not yet exited. If no appropriate handler, else clause, or statement list is found there, the search propagates to the next-most-recently entered try...except statement, and so forth. If the outermost try...except statement is reached and the exception is still not handled, the program terminates.
When an exception is handled, the
stack is traced back to the procedure or function containing the try...except
statement where the handling occurs, and control is transferred to the executed
exception handler, else clause, or statement list. This process discards
all procedure and function calls that occurred after entering the try...except
statement where the exception is handled. The exception object is then
automatically destroyed through a call to its Destroy destructor and
control is passed to the statement following the try...except statement.
(If a call to the Exit, Break, or Continue standard
procedure causes control to leave the exception handler, the exception object
is still automatically destroyed.)
In the
example below, the first exception handler handles division-by-zero exceptions,
the second one handles overflow exceptions, and the final one handles all other
math exceptions. EMathError appears last in the exception block because
it is the ancestor of the other two exception classes; if it appeared first,
the other two handlers would never be invoked.
try
...
except
on EZeroDivide do
HandleZeroDivide;
on EOverflow do
HandleOverflow;
on EMathError do
HandleMathError;
end;
An
exception handler can specify an identifier before the name of the exception
class. This declares the identifier to represent the exception object during
execution of the statement that follows on...do. The scope of the
identifier is limited to that statement. For example,
try
...
except
on E: Exception do
ErrorDialog(E.Message, E.HelpContext);
end;
If the
exception block specifies an else clause, the else clause handles
any exceptions that aren’t handled by the block’s exception handlers. For
example,
try
...
except
on EZeroDivide do
HandleZeroDivide;
on EOverflow do
HandleOverflow;
on EMathError do
HandleMathError;
else
HandleAllOthers;
end;
Here, the
else clause handles any exception that isn’t an EMathError.
An
exception block that contains no exception handlers, but instead consists only
of a list of statements, handles all exceptions. For example,
try
...
except
HandleException;
end;
Here, the HandleException routine handles any exception that occurs as a result of executing the statements between try and except.
Raising and handling
exceptions
异常可以在try...except语句中被处理。例如,
try
X := Y/Z;
except
on EZeroDivide do
HandleZeroDivide;
end;
这里的语句试图用Y除以Z,而如果引发一个EZeroDivide异常时则调用一个名为HandleZeroDivide的例程。
try...except语句的语法是
try statements except exceptionBlock end
这里的statemens是一个语句序列(分号隔开的),exceptionBlock是下列二者之一
·另一个语句序列,或者
·异常处理程序的序列,可选择地跟随
else statements
异常处理程序具有如下形式
on identifier: type do statement
这里的identifier:是可选的(如果包括,则identifier可以是任何有效标识符),type是一个用于表示异常的类型,statement是任何语句。
try...except语句执行最初的statements语句序列。如果没有异常被引发,那么异常块(exceptionBlock)被忽略并且控制被传递到程序的下一部分。
如果在执行最初的statements序列中引发了异常,那么,或者被statements序列中的raise语句,或者被statements序列中的过程或函数调用,都将尝试完成处理异常:
· 如果异常块中的任意一个处理程序与引发的异常相匹配,那么控制被传递到第一个匹配的项。异常处理程序与异常相匹配,是指处理程序中type表示的类与是异常所属的类或其祖先类。
· 如果没有发现匹配的异常处理程序,那么控制被传递到else子句中的statements语句序列(如果有该语句序列)。
· 如果异常块是一个不含有任何异常处理程序的语句序列,那么控制被传递到语句序列中的第一条语句。
如果上述条件都不满足,那么将继续在下一个最近的入口try...except语句(尚未退出之前)的异常块中搜索。如果没有发现合适的处理程序、else子句或语句序列,那么搜索将延伸到下一个最近的入口try...except语句,等等。如果最外层的try...except语句被搜索过并且异常仍然没有被处理,那么程序终止。
当一个异常被处理时,堆栈将追踪回溯到包含了处理发生时try...except语句的过程或函数,并且控制被传递到执行过的异常处理程序、else子句或相关的语句序列。这一处理过程将丢弃所有在进入异常被处理的try...except语句之后出现的过程和函数调用。这时异常对象通过对其Destroy析构器的调用被自动释放,并且控制被传递到随后的try...except语句。(如果对Exit、Break或Continue等标准过程的调用导致控制离开了异常处理程序,那么异常对象仍然会自动销毁。)
下面的例子中,第一个异常处理程序处理零除异常,第二个处理溢出异常,最后一个处理所有的数学异常。EMathError异常出现在异常块的最后,是因为它是其他两个异常类的祖先类;如果它出现在首位,那么其他两个异常处理程序将决不会被调用。
try
...
except
on EZeroDivide do
HandleZeroDivide;
on EOverflow do
HandleOverflow;
on EMathError do
HandleMathError;
end;
异常处理程序可以在异常类的名称之前指定一个标识符。如此声明的标识符用于在随后的on...do语句执行的全程中表示当前的异常对象。标识符的作用域仅限于on...do语句。例如,
try
...
except
on E: Exception do ErrorDialog(E.Message,
E.HelpContext);
end;
如果异常块指定了else子句,那么else子句负责处理在当前块中尚未被异常处理程序处理的其他任何异常。例如,
try
...
except
on EZeroDivide do
HandleZeroDivide;
on EOverflow do
HandleOverflow;
on EMathError do
HandleMathError;
else
HandleAllOthers;
end;
这里,else子句处理任何非EMathError异常。
异常块中没有任何异常处理程序,而只是由语句序列组成,这样的异常块将处理所有的异常。例如,
try
...
except
HandleException;
end;
这里,HandleException例程负责处理在try和except之间语句执行导致出现的任何异常。