The Three Exception Classes in
ABAP
So far, we have been stating that all exceptions must be declared at the interface and that this is checked at design time and runtime. Indeed, this applies only to exceptions that inherit from the class CX_STATIC_CHECK.
Some errors can occur everywhere in a program – for example, resource bottlenecks. You can deal with such errors in three ways:
· You could declare them in each interface and in this way fill the interface with useless information.
· You could catch them locally, although there is perhaps a suitable, central handler for them further up in the call hierarchy.
· You could write empty handlers so that your program complies with the compiler check rules in this way. But this is the worst alternative. Do not take this route: If the corresponding error for which the exception is thrown actually does occur, you cannot find it.
For such general exceptions we have the class CX_NO_CHECK in ABAP. You cannot and must not declare exceptions that inherit from this class in the interface. In general, nobody can react appropriately to a resource bottleneck and handle it – unless it is very far up in the call hierarchy.
Sometimes an exception could occur, but you are sure that it could not occur in your program. This is also the case with the exception CX_SY_ZERO_DIVISION. However, you can be sure that you will not divide by zero in your program if the divisor is the result of a calculation whereby zero cannot end up being the result. In this case you do not want to handle the corresponding exception nor do you want to declare it at the interface because you can prevent its occurrence.
In such cases, the question at heart is that you can prevent a certain exception from occurring by having control over a precondition or by checking it. Therefore, it would be appropriate if – in such situations – you had the choice of checking a precondition yourself or of taking care of the corresponding exception through declaration or through exception handling. The class CX_SY_DYNAMIC_CHECK is provided for such cases.
The compiler does not perform a static check as to whether an exception of this type is handled or declared. At runtime, however, these exceptions can only leave the interface – should they still occur – if they are declared at the interface.
There are three categories of exceptions:
CX_STATIC_CHECK: Exceptions of this class must be declared in the interface if they are not handled locally. Otherwise, the compiler issues a warning. This comparatively weak reaction is based on the fact that it would not be appropriate to invalidate an entire program because of an exception that is possibly hardly thrown at all. At runtime, the error CX_SY_NO_HANDLER is thrown in such a case. The original exception is passed as a value of the PREVIOUS attribute to the new exception. Always, only one exception can be active in a program and control the flow.
CX_DYNAMIC_CHECK: Declaration of this exception is not checked at design time. At runtime, the exception can only leave the interface if it is declared.
CX_NO_CHECK: This exception can leave a procedure whatever the case. There is no check at runtime or at design time.
The syntax of these three exception classes is easier to understand than having a clear perception of when you should use a particular class.
This is the suitable exception class for exceptions that can occur almost everywhere. If you use CX_DYNAMIC_CHECK or CX_STATIC_CHECK instead, the caller of your procedure will write empty handlers or will place them in an exception of the type CX_NO_CHECK.
Choose this class if your exception can be handled appropriately by a local handler. If you choose the dynamic type, there will no longer be any guarantee that your exception will always be handled. If you choose CX_NO_CHECK, this would have the disadvantage that this exception could now occur anywhere in your program. If it actually does occur, it would be very difficult to find its origin.
You use this class if someone can prevent an exception by checking a precondition. The person responsible fort his check is also responsible later on when the corresponding exception is thrown.
A typical example of this is division by zero. The person responsible for this exception is the person in the call hierarchy who makes the divisor available. If you perform a division operation and the divisor comes from your caller, you should declare the exception at the interface – while the person who supplies the divisor should check the precondition or handle the exception.
If everyone adheres to this rule, it is easy to find out who is responsible for the exception. It is the person who has forgotten to check the precondition or to declare the exception at the interface.
If you choose the static type instead, you force the declaration, although the precondition of the exception can be checked or you encourage others to write empty handlers.