An exception is an exceptional condition in a program, generally associated with an error that could make a program crash. Exceptions provide the means to handle errors in an elegant and robust manner. Exceptions provide the means to separate error handling from the rest of the code and it also provides a consistent way of reporting errors.
There are many errors that a programmer should trap with standard program code, rather than leaving it to Delphi to handle them, for example checking that a number is positive before trying to find its square root or that a divisor is not zero. The exceptions mechanism is provided for detecting system errors such as a faulty file or a printer being unavailable, it is not a safety-net for poor programming practice.
Delphi provides two related constructions for dealing with exceptions, the try-except statement that can deal with exceptions or errors, and the try-finally statement that guarantees the code in the finally section will run even if an error occurs. Delphi raises exceptions at run-time when something goes wrong. There are just four keywords used to provide handling for exceptions:
try - starts a protected block of code
finally - specifies blocks of code that must be executed, even when exceptions occur; cannot be used at the same time as except
except - ends a protected block of code and introduces exception-handling code; cannot be used at same time as finally
raise - raises exceptions explicitly instead of waiting for Delphi to raise them
Places where an exception structure might be used include file processing and printing, both situations where errors might occur due to failure of hardware. When processing a file there may be a disc error, the file may be corrupted or it may not be in the path specified, and we would, in all these cases, want to make sure that the error was identified and that the program closed down the file correctly. When printing we need to make sure that the program will overcome problems like the printer being unavailable (off-line, switched off, or paused due to a technical problem such as a paper jam).
The finally keyword should be used whenever a method performs some tidying up or finalising when it finishes. For example:
if PrintDialog1.Execute then
begin
try
AssignPrn (FPrn);
Rewrite (FPrn);
writeln (FPrn, 'To dance beneath the diamond sky with one hand waving free');
finally
CloseFile (FPrn);
end;
end;
Whenever there is some finalisation code at the end of a method you should use a finally block to protect the code and to prevent resource or memory leaks (filling up memory and not reclaiming it). Here the assigned printer file FPrn is closed even if the attempt to open it and write something to it fail. Similarly with files, to avoid problems when reading from a file:
if OpenDialog1.Execute then
begin
try
filename:=OpenDialog1.FileName;
Assignfile(intfilename, filename);
reset (intfilename);
while not eof (intfilename) do
begin
read(intfilename,rec);
memo1.lines.add (rec.name);
end;
finally
closefile(intfilename);
end;
end;
In the following example a try...except structure is used to trap potential file errors, specifically the failure to create a file.
procedure TForm1.Open1Click(Sender: TObject);
resourcestring
sCannotCreate='Cannot create file: %s';
begin
if OpenDialog1.Execute then
begin
try
filename:=OpenDialog1.FileName;
Assignfile(filename, filename);
reset (filename);
while not eof (filename) do
begin
read(filename,rec);
memo1.lines.add (rec.name);
end;
except
on Ex: EFCreateError do
raise EFileCopyError.CreateFmt(sCannotCreate, [Ex.Message]);
end; //try
closefile(filename);
end; //if
end;
The following example uses the division by zero situation to illustrate the use of exceptions:
procedure TForm1.divide;
begin
a:=strtoint(inputbox('Enter first integer','First Integer', '1'));
b:=strtoint(inputbox('Enter second integer','Second Integer', '1'));
Screen.cursor:=crHourglass;
try
try
c:=a div b;
showmessage ('Answer is ' + inttostr(c));
finally
Screen.cursor:=crDefault;
end;
except
on EDivByZero do
raise Exception.Create('Division by zero. Cannot complete
operation.');
end;
end;
Here we have a try..finally nested inside a try..except structure. The syntax for try..finally is relatively simple but that for try..except can be more complicated. In this case we use a pre-defined exception, EDivByZero, along with the Exception object and one of its methods, Create, to raise an error and supply a message to the user if the divide by zero error occurs.
We could have written the exception handler like this:
on Ex: EDivByZero do
raise Exception.Create('Division by zero. Cannot complete
operation.');
The slight difference here is the introduction of an exception variable, Ex. The programmer does not need to define Ex or Exception in advance. The object Ex, which is of class Exception type, receives the value of the exception object passed by the raise statement. The exception object is raised and then handled by reference to its type.
Note that there is a difference in behaviour of the exception handling routines when a program is being debugged in the IDE and when it is running independently. When debugging Delphi displays the system messages regarding the error:

However, when the program is running outside the Delphi environment (double-click the .exe file) the system messages will be intercepted and the programmer's own messages will be displayed.

To stop the display of system error messages from within the debugger select Tools/Debugger Options, the Language Exceptions tab and un-tick the Stop on Delphi Exceptions mark.
Other built-in exceptions include: EExternal (whose derived classes include EAccessViolation, EControlC, EIntError, EMathError and EStackOverflow), EConvertError, EInOutError, EPackageError and EWin32Error (see TException for further details). If you think that your program may raise any of these errors then you should consider replacing the default error handler with one of your own in the way illustrated above. On the other hand, you should leave unknown exceptions to Delphi and not try to devise your own routines to handle them: leave them to the onException event of the global Application object.