This commit is contained in:
danrega
2024-11-04 16:42:58 +01:00
parent e3e20c72c6
commit cb2ecc4ca7
3 changed files with 2686 additions and 217 deletions

View File

@@ -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.
<p align="right"><a href="#top">⬆️ back to top</a></p>
## 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**<br>
> - Non-class-based exceptions are considered obsolete and should not be defined any more in new developments according to the [guidelines (F1 docu for standard ABAP)](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abenclass_exception_guidl.htm) and are not dealt with here.
>- For all exceptions that are raised by the ABAP runtime environment and that are not handled, there is a corresponding runtime error. For example, in the case of exception class `CX_SY_ZERODIVIDE`, it is the runtime error `COMPUTE_INT_ZERODIVIDE`. For self-defined exception classes, an exception that is not handled generally triggers the runtime error `UNCAUGHT_EXCEPTION`.
> - For `TRY` control structures, there are further additions available dealing with more advanced error handling, e. g. [resumable exceptions](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapresume.htm).
<p align="right"><a href="#top">⬆️ back to top</a></p>
#### Notes on Exception Classes
- To distinguish exception classes from *regular* classes, use the naming convention `CX` as prefix and not `CL`.
- All exception classes (also the self-defined ones) are directly or indirectly derived from three abstract subclasses: `CX_STATIC_CHECK`, `CX_DYNAMIC_CHECK` and `CX_NO_CHECK`. These three "exception class categories" have different properties.
- The class `CX_ROOT` is the root class. Directly deriving from `CX_ROOT` is not possible.
- Apart from global classes, exception classes can also be defined as local classes within an ABAP program.
- As mentioned, there are predefined exception classes like `CX_SY_ZERODIVIDE` for divisions by zero. However, you can create your own exception classes so that you can react on issues that are specific to your ABAP program. The exception class must, as stated above, be derived from one of the three abstract classes:
- `CX_STATIC_CHECK`: For forcing users to handle exceptions.
Generally speaking, exceptions that can occur in procedures should be handled locally there in the implementation or be declared explicitly in the [procedure interface](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abenparameter_interface_glosry.htm) so that a caller knows which error situations can be expected. Exception classes of type `CX_STATIC_CHECK` enforce this. A check is carried out statically at compile time. Users of a procedure are then forced to either handle the exception locally in a `TRY` control structure or the users declare the exception themselves in their procedure interface to propagate the exception to their users. If this is not the case, a warning is produced.
- As an example, a method signature might look as follows. The addition `RAISING` in method signatures is used to declare one or more class-based exceptions that can be propagated from the method to the caller.
- When users of this method implement the method, they are made aware of the fact that an error situation can occur and a particular exception can be raised. The assumption is that `CX_SOME_ERROR` is derived from `CX_STATIC_CHECK`. Users of the method should then prepare the code accordingly.
```abap
"Method definition using the RAISING parameter
CLASS-METHODS: some_meth IMPORTING str TYPE string
RETURNING VALUE(ret_value) TYPE string
RAISING cx_some_error.
...
"Method call: Somewhere in the code of a user that calls the method
"Exception handled locally in a TRY control structure.
TRY.
DATA(val) = some_meth( str = `hallo` ).
CATCH cx_some_error.
...
ENDTRY.
"If it was just like this without the TRY control structure, a warning would be produced.
DATA(val2) = some_meth( str = `hi` ).
```
- `CX_DYNAMIC_CHECK`: For exceptions that can be checked and avoided by preconditions. As a consequence and in contrast to an exception class derived from `CX_STATIC_CHECK`, exception classes of type `CX_DYNAMIC_CHECK` do not enforce the local handling and the declaration in procedure interfaces. However, an appropriate exception handling should be implemented in cases in which you cannot rule out the raising of the exceptions in your program logic. The checking if a local handling or an explicit declaration in procedure interfaces is available is carried out at runtime only ("dynamic check") and only in case the exception is indeed raised.
- If it is determined at runtime that such an exception is neither locally handled nor an interface is declared appropriately - and the exception is raised - a new exception of type `CX_SY_NO_HANDLER` is raised. In this case, the attribute `PREVIOUS` contains a reference to the original exception.
- Example: The predefined class `CX_SY_ZERODIVIDE` is derived from `CX_DYNAMIC_CHECK`. The operands of a calculation can be checked appropriately (e. g. in case of a division, the implementation should guarantee that the second operand is not 0) before carrying out the arithmetic operation. In doing so, the exception can be avoided.
- `CX_NO_CHECK`: For error situations that can basically occur any time, cannot be locally handled in a meaningful way or cannot be avoided even following a check. An example for such an error situation might be a lack of memory. If the handling of such exceptions was checked statically or dynamically, it would basically mean to specify it in each procedure interface - not ideal for a clear program structuring.
- Note that exceptions derived from `CX_NO_CHECK` are always declared implicitly in all procedure interfaces.
**Basic rule**: [Use a suitable exception category (F1 docu for standard ABAP)](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abenexception_category_guidl.htm).
> **💡 Note**<br>
> - Each exception has a an [exception text](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abenexception_text_glosry.htm) that describes the error situation and that you can retrieve as outlined above. It helps you analyze the error. Plus, imagine using exceptions in the context of user interfaces. If a user faces an error situation, such exception texts may be displayed on the UI.
> - Find more information on exception texts [here](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abenexception_texts.htm) in the ABAP Keyword Documentation.
<p align="right"><a href="#top">⬆️ back to top</a></p>
### Raising Exceptions
- Either the ABAP runtime framework raises predefined exceptions or you raise exceptions programmatically using dedicated statements. You can raise both predefined and self-defined exceptions.
- As the name implies, [`RAISE EXCEPTION`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapraise_exception_class.htm) statements raise class-based exceptions and thus interrupt the execution of the current statement block.
- The `COND` operator includes the optional addition `THROW` to raise class-based exceptions.
```abap
...
"RAISE EXCEPTION statement
"The TYPE addition specifies the type of the exception, i. e. the exception class.
"The statement is also possible without TYPE. In that case, you can use an existing exception object.
"Note that there are plenty of additions. Check the ABAP Keyword Documentation.
RAISE EXCEPTION TYPE cx_sy_zerodivide.
...
"THROW addition for the COND operator
... = COND #( WHEN ... THEN ...
WHEN ... THEN ...
ELSE THROW cx_some_error( ) ).
```
<p align="right"><a href="#top">⬆️ back to top</a></p>
## Excursion: Runtime Errors and Terminating Programs
- Runtime errors are caused by uncatchable exceptions when a program is executed, when a catchable exception is not caught, or they can be forced by, for example, using [`ASSERT`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapassert.htm) statements.
- Every runtime error terminates the program, which in turn raises a [database rollback](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendatabase_rollback_glosry.htm) and is documented by default in a [short dump](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenshort_dump_glosry.htm).
- Regarding `ASSERT` statements: `ASSERT` is followed by a logical expression. If the expression is false, the program is terminated and an uncatchable exception is raised resulting in the runtime error `ASSERTION_FAILED`. Note that each runtime error is identified by a name and assigned to a specific error situation.
```abap
"The ASSERT keyword is followed by a logical expression.
"If the expression is false, the program is terminated and an uncatchable exception is raised
"resulting in the runtime error ASSERTION_FAILED.
DATA(number) = 0.
ASSERT number IS INITIAL.
ASSERT number > -1.
ASSERT 1 = 1.
DATA(flag) = abap_false.
"Raises a runtime error
ASSERT flag = abap_true.
```
> **💡 Note**<br>
> - Each runtime error is identified by a name and assigned to a specific error situation.
> - In ADT, you will see a message popping up and informing you about the runtime error. You can check the details by choosing the "Show" button in the pop-up. Furthermore, you can check the content of the "Feed Reader" tab in ADT. There, just expand your project and find the runtime errors caused by you.
Exceptions and runtime errors affect the program flow. Find an overview in the [Exceptions and Runtime Errors](27_Exceptions.md) cheat sheet.
<p align="right"><a href="#top">⬆️ back to top</a></p>

2681
27_Exceptions.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -94,6 +94,8 @@ ABAP cheat sheets[^1] ...
|[Misc Built-In Functions](24_Misc_Builtin_Functions.md)|Covers a variety of built-in functions in ABAP|- (The cheat sheet includes copy and paste code snippets)|
|[Authorization Checks](25_Authorization_Checks.md)|Provides a high-level overview of explicit and implicit authorization checks in ABAP|- (The cheat sheet includes a copy and paste example class)|
|[ABAP Dictionary](26_ABAP_Dictionary.md)|Covers a selection of repository objects in the ABAP Dictionary (DDIC) that represent global types|- (The cheat sheet includes a copy and paste example class)|
|[Exceptions and Runtime Errors](27_Exceptions.md)|Provides an overview on exceptions and runtime errors|- (The cheat sheet includes a copy and paste example class)|
<br>