TRY
Topic group Related topics Example
A control statement used to handle exceptions and other deviations of program flow.
Syntax
TRY
<statement block 1>
CATCH( <exception type1> <exception oRef1> )
<statement block 2>
[ CATCH( <exception type2> <exception oRef2> )
<statement block 3> ]
[ CATCH ... ]
[ FINALLY
<statement block 4> ]
ENDTRY
TRY <statement block 1>
A statement block for which the following CATCH or FINALLY block—or both—will be used if an exception occurs during execution. A TRY block must be followed by either a CATCH block, a FINALLY block, or both.
CATCH <statement block 2>
A statement block that is executed when an exception occurs. The first CATCH or FINALLY is not optional and must be included.
<exception type>
The class name of the exception to look for—usually, Exception.
<exception oRef>
A formal parameter to receive the Exception object passed to the CATCH block.
CATCH...
Catch blocks for other types of exceptions.
FINALLY <statement block 4>
A statement block that is always executed after the TRY block, even if an exception or other deviation of program flow occurs. If there is both a CATCH and a FINALLY, the FINALLY block executes after the CATCH block.
ENDTRY
A required keyword that marks the end of the TRY structure.
Description
An exception is a condition that is either generated by dBASE Plus, usually in response to an error, or by the programmer. By default, dBASE Plus handles an exception by displaying an error dialog and terminating the currently executing program. You can use FINALLY to make sure some code gets executed even if there is an exception, and CATCH to handle the exception yourself, in the following combinations:
For a block of code that may generate an exception, place the code inside a TRY block. To prevent the exception from generating a standard error dialog and terminating execution, place exception handling code in a CATCH block after the TRY. If an exception occurs, execution immediately jumps to the CATCH block; no more statements in the TRY block are executed. If no exception occurs, the CATCH block is not executed.
If there’s some code that should always be executed at the end of a process, whether or not the process completes successfully, place that code in a FINALLY block. With TRY and FINALLY but no CATCH, if an exception occurs during the TRY block, execution immediately jumps to the FINALLY block; no more statements in the TRY block are executed. Since there was no CATCH, you would still have an exception, which if not handled by a higher-level CATCH as described later, dBASE Plus would handle as usual, after executing the FINALLY block. If no exception occurs, the FINALLY block is executed after the TRY.
If you have all three—TRY, CATCH, and FINALLY—if an exception occurs, execution immediately jumps to the CATCH block; after the CATCH block executes, the FINALLY block is executed. If there is no exception during the TRY, then the CATCH block is skipped, and the FINALLY block is executed.
The code that is covered by TRY doesn’t have to be inside the statement block physically; the coverage exists until that entire block of code is executed. For example, you may have a function call inside a TRY block, and if an exception occurs while that function is executing—even if that function is defined in another program file—execution jumps back to the corresponding CATCH or FINALLY.
A TRY block may be followed by multiple CATCH blocks, each with its own <exception type>. When an exception occurs, dBASE Plus compares the <exception type> with the className property of the Exception object. If they match, that CATCH block is executed and all others are skipped. If the className does not match, dBASE Plus searches the class hierarchy of that object to find a match. If no match is found, the next CATCH block is tested. Class name matches are not case-sensitive. For example, the DbException class is a subclass of the Exception class. If the blocks are arranged like this:
try
// Statements
catch ( DbException e )
// Block 1
catch ( Exception e )
// Block 2
endtry
and a DbException occurs, execution goes to Block 1, because that’s a match. If an Exception occurs, execution goes to Block 2, because Block 1 doesn’t match, but Block 2 does. If the blocks are arranged the other way around, like this:
try
// Statements
catch ( Exception e )
// Block 1
catch ( DbException e )
// Block 2
endtry
then all exceptions always go to Block 1, because all Exceptions are derived from the Exception class. Therefore, when using multiple CATCH blocks, list the most specific exception classes first.
You can generate exceptions on purpose with the THROW statement to control program flow. For example, if you enter deeply nested control structures or subroutines from a TRY block, you can THROW an exception from anywhere in the nested code. This would cause execution to jump back to the corresponding CATCH or FINALLY, instead of having to exit each control structure or subroutine one-by-one.
You may also nest TRY structures. An exception inside the TRY block causes execution to jump to the corresponding CATCH or FINALLY, but an exception in a CATCH or FINALLY is simply treated as an exception. Also, if you have a TRY and FINALLY but no CATCH, that leaves you with an unhandled exception. If the TRY/CATCH/FINALLY is itself inside a TRY block, then that exception would be handled at that next higher level, as illustrated in the following code skeleton:
try
// exception level 1
try
// exception level 2
catch ( Exception e )
// handler for level 2
// but exception level 1
finally
// level 2
endtry
catch ( Exception e )
// handler for level 1
endtry
Note that if an exception occurs in the level 2 CATCH, the level 2 FINALLY is still executed before going to the level 1 CATCH, because a FINALLY block is always executed after a TRY block.
In addition to exceptions, other program flow deviations—specifically EXIT, LOOP, and RETURN—are also caught by TRY. If there is a corresponding FINALLY block, it’s executed before control is transferred to the expected destination. (CATCH catches only exceptions.)