diff --git a/13_Program_Flow_Logic.md b/13_Program_Flow_Logic.md index 6eaa69e..34c0429 100644 --- a/13_Program_Flow_Logic.md +++ b/13_Program_Flow_Logic.md @@ -24,10 +24,7 @@ - [Subroutines in Standard ABAP](#subroutines-in-standard-abap) - [Excursion: RETURN](#excursion-return) - [Interrupting the Program Execution](#interrupting-the-program-execution) - - [Handling Exceptions](#handling-exceptions) - - [Notes on Exception Classes](#notes-on-exception-classes) - - [Raising Exceptions](#raising-exceptions) - - [Excursion: Runtime Errors and Terminating Programs](#excursion-runtime-errors-and-terminating-programs) + - [Exceptions and Runtime Errors](#exceptions-and-runtime-errors) - [Executable Example](#executable-example) @@ -927,220 +924,9 @@ ASSERT seconds > 4.
-## Handling Exceptions -- [Exceptions](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenexception_glosry.htm) ... - - are events during the execution of an ABAP program that interrupt the program flow because it is not possible for the program to continue in a meaningful way. For such situations, you can implement an exception handling in which you can react on the situations appropriately. Consider, for example, the implementation of a simple calculation. If there is a division by zero, the program will be terminated with a [runtime error](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenruntime_error_glosry.htm) unless you handle the exception appropriately. - - can be raised either by the program or by the [ABAP runtime framework](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabap_runtime_frmwk_glosry.htm). Exceptions raised by the latter are generally caused by error situations that cannot be detected by the static program check. The division by zero is such an example. - - should, in modern ABAP, only be designed as [class-based exceptions](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenclass_based_exception_glosry.htm), i. e. exceptions are represented by [objects](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenobject_glosry.htm) of classes. Global exception classes usually use the naming convention `CX_...`. - - are either [catchable](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abencatchable_exception_glosry.htm) (they are based on predefined or self-defined exception classes) or [uncatchable](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenuncatchable_exception_glosry.htm) (they directly produce runtime errors, i. e. error situations cannot be handled appropriately). +## Exceptions and Runtime Errors -`TRY` control structures are meant for handling catchable exceptions locally: -- To be prepared for potential exceptions that are raised when executing statements, the statements can be included and executed within a *protected area*, a [`TRY`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abaptry.htm) control structure. -- In doing so, it is possible for the ABAP runtime framework to catch exceptions and react on error situations. - - ```abap - TRY. - "statement block - ENDTRY. - ``` - -- The `TRY` control structure in the snippet above produces a syntax warning. A [`CATCH`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapcatch_try.htm) block is expected, too. -- One or more class-based exceptions can be handled in one or more subsequent `CATCH` blocks. The `CATCH` statement must include an "appropriate" class-based exception. "Appropriate" means that, certainly, an exception class should be specified that is suitable for the error handling. In the following example, the predefined exception class `CX_SY_ZERODIVIDE` is specified that is, as the name implies, specific for the (potential) exception in case of a division by zero. - - ```abap - TRY. - "TRY block - DATA(div1) = 1 / 0. - - "Predefined exception class cx_sy_zerodivide as suitable exception class to be used here. - "If the exception is not handled, the program is terminated and the runtime error - "COMPUTE_INT_ZERODIVIDE occurs. - CATCH cx_sy_zerodivide. - ... "CATCH block - ENDTRY. - - "Example for catching an exception in the context of a table expression - TRY. - "Copying a line of an internal table - DATA(line) = some_itab[ 12345 ]. - - "Predefined exception class cx_sy_itab_line_not_found as suitable exception class to be used here. - "If the exception is not handled, the program is terminated and the runtime error - "ITAB_LINE_NOT_FOUND occurs. - CATCH cx_sy_itab_line_not_found. - ... "CATCH block - ENDTRY. - - "Note on inheritance relationships in exception classes - TRY. - "TRY block - DATA(div2) = 1 / 0. - - "A CATCH block is in this example not only valid for cx_sy_zerodivide as specified above - "but also for all derived exceptions classes. - "In the following CATCH block, the predefined exception class cx_sy_arithmetic_error - "is specified. cx_sy_zerodivide is derived from cx_sy_arithmetic_error. - "Hence, cx_sy_arithmetic_error can be specified and handle the exception, too. - "Basically, using the exception root class cx_root would be also possible. However, - "choosing an appropriate exception class is recommended. See further down. - - CATCH cx_sy_arithmetic_error. - ... "CATCH block - ENDTRY. - - - "Multiple classes in a list and CATCH blocks can be specified - "Note: If there are multiple CATCH blocks for exceptions that are in an inheritance - "relationship, you must pay attention that the more special exceptions are specified - "before the more general ones. - TRY. - ... "TRY block - CATCH cx_abc cx_bla cx_blabla. - ... "CATCH block - CATCH cx_la cx_lala. - ... "CATCH block - CATCH cx_lalala. - ... "CATCH block - ENDTRY. - ``` - -- If the addition `INTO` is specified in the `CATCH` statement, a reference to the exception object is stored. -- This is relevant to determine the exact exception, for example. In the code snippet above, the exception class `CX_SY_ZERODIVIDE` is mentioned. Consider a calculator. It should not only be able to deal with error situations like zero division but also, for example, overflows in arithmetic operations. The predefined exception class `CX_SY_ARITHMETIC_OVERFLOW` is available. It is also derived from `CX_SY_ARITHMETIC_ERROR`. If you then specify the exception class `CX_SY_ARITHMETIC_ERROR` which is higher up in the inheritance hierarchy and can handle both error situations (`CX_SY_ARITHMETIC_OVERFLOW` and `CX_SY_ZERODIVIDE`), the concrete exception that was raised is unclear. Using the `INTO` clause and the stored exception object, it is possible to carry out certain tasks, for example, retrieving and displaying the exception text. - - ```abap - DATA: exception TYPE REF TO cx_root. "Note the root class - "Note: For a self-defined exception class, the object reference must be typed appropriately. - - TRY. - ... "TRY block - - "Storing a reference to the exception object. - "Note: The type is cx_root since attributes and methods of the root class that are defined there can be accessed. - CATCH INTO exception. - ... "CATCH block - ENDTRY. - - "Inline creation of exception object reference and getting exception texts - TRY. - ... "TRY block - - "The object reference variable can be created inline, for example, using DATA(...). - CATCH cx_sy_arithmetic_error INTO DATA(error_oref). - ... "catch block - "To get exception texts, you can call, for example, the method get_text - DATA(error_text) = error_oref->get_text( ). - - ENDTRY. - ``` - -- Regarding the program flow: - - The statement block following `TRY.` is always processed. If an exception is raised within this `TRY` block, the system searches for an exception handler, i. e. a `CATCH` block that is able to handle the exception. - - If there is no `CATCH` statement that is able to handle the catchable exception or if erroneous code is not within a `TRY` control structure at all, the exception is propagated to the caller. - - Exceptions can be handled either in the context locally (using such a `TRY` control structure) or be propagated to the caller so that the caller is responsible for reacting appropriately (for example, in another `TRY` control structure) to the error situation. In doing so, you can better structure your code by reacting on error situations centrally instead of locally checking, for example, each procedure call individually. - - If, at the end, the exception can nowhere be caught and handled, the program is terminated with a runtime error. - - If the exception can be handled or no exception is raised in the `TRY` block and it reaches its end, the processing continues after `ENDTRY`. - - -> **💡 Note**| Superclass of Exception Classes | Notes | +
| + +`CX_STATIC_CHECK` + + | + ++ +- Users must handle exceptions. +- Exceptions that may occur in procedures should be handled locally within the implementation or explicitly declared in the [procedure interface](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abenparameter_interface_glosry.htm) so callers know what errors to expect. +- Exception classes of type `CX_STATIC_CHECK` enforce this by performing a static check at compile time. Procedure users must handle the exception locally in a `TRY` control structure or declare it in their procedure interface to propagate the exception. If not, a warning is produced. + +Example: + +- A method signature might look like this. The `RAISING` addition in method signatures declares one or more class-based exceptions that can be propagated to the caller. +- When users implement the method, they are aware that an error might occur, and a specific exception can be raised. +- `CX_UUID_ERROR` is a predefined exception class derived from `CX_STATIC_CHECK`. Method users should prepare their code accordingly. + ```abap + "Method definition using the RAISING parameter + CLASS-METHODS get_uuid + RETURNING VALUE(uuid) TYPE sysuuid_x16 + RAISING cx_uuid_error. + + ... + + "Method implementation + METHOD get_uuid. + uuid = cl_system_uuid=>create_uuid_x16_static( ) . + ENDMETHOD. + + ... + + "Method call: Somewhere in the code of a user that calls the method + "Exception handled locally in a TRY control structure + TRY. + DATA(uuid) = get_uuid( ). + + CATCH cx_uuid_error. + ... + ENDTRY. + + "If the statement is specified without the TRY control structure, + "a warning is shown. + DATA(uuid2) = get_uuid( ). + ``` + + | +
| + +`CX_DYNAMIC_CHECK` + + | + +
+
+
+- For exceptions that can be checked and avoided by preconditions:
+- Unlike exception classes derived from `CX_STATIC_CHECK`, exception classes derived from `CX_DYNAMIC_CHECK` do not enforce local handling or declaration in procedure interfaces.
+- However, proper exception handling is necessary when you cannot prevent the exceptions from being raised in your program logic.
+- Runtime checks verify whether local handling or explicit declaration in procedure interfaces are available only if the exception is raised.
+- If, at runtime, such an exception is neither locally handled nor properly declared in an interface and the exception is raised, a new exception of type `CX_SY_NO_HANDLER` is raised, with the `PREVIOUS` attribute referencing the original exception.
+
+Example:
+- The predefined class `CX_SY_ZERODIVIDE` is derived from `CX_SY_ARITHMETIC_ERROR`, which is derived from `CX_DYNAMIC_CHECK`.
+- Operands in a calculation should be checked (e.g., ensuring the second operand is not 0 in a division) before performing the arithmetic operation to avoid exceptions.
+
+ + + + ```abap + "Method definition using the RAISING parameter + CLASS-METHODS divide + IMPORTING num1 TYPE i + num2 TYPE i + RETURNING VALUE(div_result) TYPE decfloat34 + RAISING cx_sy_zerodivide. + + ... + + "Method implementation + METHOD divide. + div_result = num1 / num2. + ENDMETHOD. + + ... + + "Method call: Somewhere in the code of a user that calls the method + "Unlike procedures specifying an exception class derived from CX_STATIC_CHECK, + "procedures specifying an exception class derived from CX_DYNAMIC_CHECK do not + "enforce the local handling of exceptions. So, the following statement does + "not show a warning. + DATA(div_result1) = divide( num1 = 5 num2 = 2 ). + + "Exception handled locally in a TRY control structure + TRY. + DATA(div_result2) = divide( num1 = 5 num2 = 0 ). + CATCH cx_sy_zerodivide. + ENDTRY. + ``` + + |
+
| + +`CX_NO_CHECK` + + | + ++ +- For errors that may occur anytime, cannot be handled locally in a meaningful way, or cannot be avoided even after a check. +- An example of such an error is a lack of memory. If such exceptions were checked statically or dynamically, it would require specification in each procedure interface, which is not ideal for clear program structure. +- Note that exceptions derived from `CX_NO_CHECK` are always implicitly declared in all procedure interfaces. + + | +