ABAP OO - Exception Handling
What about error handling in object-oriented programming? We want to address this question in this article.
When you develop software, sooner or later exceptional situations arise because data is missing, something is incomplete or the user has provided incorrect data via the UI. In such cases, the code should behave correctly and not crash uncontrollably. Perhaps the user would like some feedback on his action or a logging table needs to be updated.
Let's take another look at classic error handling and what disadvantages we currently have with it. This variant still comes from the function modules and is handled in exactly the same way when defining the method. To do this, we define a method that includes two error situations:
METHODS: is_data_valid IMPORTING id_data TYPE string RETURNING VALUE(rd_result) TYPE abap_bool EXCEPTIONS empty_data wrong_key.
We use the keyword EXCEPTION to define errors that can occur in the method and that give us the opportunity to give the status to the outside world. We also create an implementation corresponding to the definition of the method. This is an example implementation and only focuses on the functionality.
METHOD is_data_valid. CASE id_data. WHEN ``. RAISE empty_data. WHEN `WRONG`. RAISE wrong_key. WHEN OTHERS. rd_result = abap_true. ENDCASE. ENDMETHOD.
In order to be able to trigger the error in an error situation and to interrupt the code at this point, we use the keyword RAISE. The current method is then interrupted and terminated; it continues at the point where the method was called. Where the error can now be handled accordingly via the SUBRC.
is_data_valid( EXPORTING id_data = `123` RECEIVING rd_result = DATA(ld_valid_string) EXCEPTIONS empty_data = 1 wrong_key = 2 OTHERS = 3 ). IF sy-subrc <> 0. " Error handling ENDIF.
At this point, the use of classic error handling is not very expedient and makes the advantages of the modern and short method calls ineffective. There are also some disadvantages that have to be considered:
- Long spelling for methods
- Transporting context information and messages is difficult
- Unnecessary keywords (exporting, receiving, exceptions)
- Abort of several methods (processing chain) difficult
The new error handling uses so-called exception classes for the forwarding and triggering of errors; these differ only minimally from normal classes and can also be handled in a similar way. To do this, we are guided by the example code of the classic example and add accordingly.
METHODS: is_data_valid_new IMPORTING id_data TYPE string RETURNING VALUE(rd_result) TYPE abap_bool RAISING cx_sy_conversion_data_loss cx_sy_table_key_specification.
As you noticed, we are now using RAISING instead of the EXCEPTION keyword, so we use exception classes for the two errors. You can recognize exception classes by their name, as they start with CX_ *. Otherwise the interface has hardly changed. Now let's take a closer look at the implementation of the method.
METHOD is_data_valid_new. CASE id_data. WHEN ``. RAISE EXCEPTION TYPE cx_sy_conversion_data_loss. WHEN `WRONG`. RAISE EXCEPTION NEW cx_sy_table_key_specification( ). WHEN OTHERS. rd_result = abap_true. ENDCASE. ENDMETHOD.
When triggering the exception, we chose two different variants, the previous variant and the new variant with the NEW keyword in the second case. In both cases, processing is aborted and the exception is raised. To do this, call the method accordingly:
DATA(ld_valid_new) = is_data_valid_new( `123` ).
The method is now very short and can be written on one line. You will notice, however, that no error handling has yet been implemented, we will do this in the next section.
In order to catch the error or to be able to react to it, you can no longer fall back on the SUBRC of the application. Here you use a new construct, the TRY/CATCH, to react to the error. Error handling could look like this:
TRY. DATA(ld_valid_new) = is_data_valid_new( `123` ). CATCH cx_sy_conversion_data_loss INTO DATA(lo_empty). " Error handling ENDTRY.
Since the method produces two different errors, we should also react to both variants. Here you have the opportunity to catch all errors in a CATCH branch or to react differently to each error. The following two examples should bring you closer to the notation:
" One Catch TRY. DATA(ld_valid_new) = is_data_valid_new( `123` ). CATCH: cx_sy_conversion_data_loss, cx_sy_table_key_specification INTO DATA(lo_error). " Error handling ENDTRY. " Separate Catch TRY. DATA(ld_valid_new) = is_data_valid_new( `123` ). CATCH cx_sy_conversion_data_loss INTO DATA(lo_empty). " Error handling CATCH cx_sy_table_key_specification INTO DATA(lo_key). " Error handling ENDTRY.
After the TRY, the code is tried to be executed until the block has ended. If there is an exception, the following code in the TRY block is no longer executed and branches directly to the corresponding CATCH, here you can carry out your error handling or your logging.
With the try / catch block you catch an error, but you don't have to do this after calling the method. In the object-oriented world, methods are usually only small sections of code and neatly encapsulated in various calls, which means that in a processing chain of methods, an error is usually triggered far down in the hierarchy. In such cases, the record that has just been processed is no longer valid and the termination occurs high up in the chain.
In such cases, the error handling is simply carried out at the desired point and a CATCH processes the error, logs it and cleanly aborts the current data record. A clear advantage for a clean structuring of software.
Hint: If an exception is not caught in the entire call stack, an exception is raised and the report terminates with a dump. This behavior can also be desired, but should be checked because processing does not end properly.
The additions CLEANUP and RESUME, which can be used within the block, should also be mentioned. These meet special requirements when the block is aborted:
- CLEANUP - Here you have the opportunity to carry out reworking, to carry out database rollbacks or to initialize internal variables.
- RESUME - Resume processing if a resumeable exception is thrown. You can find out more about this in the official documentation.
Today we showed you the concept of modern error handling using exception classes and how you can use them efficiently. In the next article we will go into more detail about the error classes and how you can optimize them for your purposes.