Что умеет Try Catch в ABAP?

от автора

Привет, сейчас мы коснёмся лучшего языка программирования ABAP, ещё бы. А точнее возможностей TRY…CATCH в разрезе данного языка. Вроде что-то «пытается» , что-то «ловит», но не всё так очевидно…

У данной конструкции открываются дополнительные возможности, если добавить такие операторы, как CLEANUP, RESUME, RETRY и BEFORE UNWIND. Обсудим для чего они нужны и как с ними работать.

CLEANUP

Блок CLEANUP будет использоваться для удаления ссылок перед завершением вызова метода. Всякий раз, когда возникает исключение, система прекращает обработку с этого момента и переходит к соответствующему блоку TRY. Из-за такого поведения объект будет находиться в промежуточном состоянии. Блок CLEANUP предоставляет нам возможность восстановить состояние объекта перед выходом из текущего блока обработки.

CLASS lcl_main DEFINITION FINAL.   PUBLIC SECTION.     METHODS:       method1,       method2. ENDCLASS. CLASS lcl_main IMPLEMENTATION.   METHOD method1.     TRY.         method2( ).       CATCH cx_root.         cl_demo_output=>write( 'catching cx_root' ).     ENDTRY.     cl_demo_output=>display( ).   ENDMETHOD.   METHOD method2.     TRY.         DATA(result) = 2 / 0.       CLEANUP.         cl_demo_output=>write( 'cleanup' ).     ENDTRY.   ENDMETHOD. ENDCLASS.  START-OF-SELECTION.   NEW lcl_main( )->method1( ).

В этом примере у нас есть «внешний» блок TRY..ENDTRY в методе method1. У нас есть «внутренний» блок TRY..ENDTRY в методе method2, который запускается из внешнего блока. Поскольку мы делим на 0, оператор деления вызовет исключение типа CX_SY_ZERODIVIDE. Поскольку мы перехватываем все исключения, используя CATCH CX_ROOT во внешнем блоке TRY, система выполнит логику блока CLEANUP во внутреннем блоке TRY.

Замените этот CX_ROOT на CX_SY_BUFFER_OVERFLOW, который не является частью иерархии CX_SY_ZERODIVIDE, поэтому CLEANUP не будет выполнена, и это приведет к дампу во время выполнения.

RESUME

С RESUME вы выходите из блока CATCH и возобновляете обработку после инструкции, вызвавшей исключение. Пример ниже отлично демонстрирует возможности RESUME.

CLASS lcl_employee DEFINITION FINAL CREATE PUBLIC.    PUBLIC SECTION.      TYPES: BEGIN OF empl_data,              empid  TYPE int4,       " Employee ID              emptyp TYPE string,     " Org Assignment data              salary TYPE decfloat16, " Pay data              phone  TYPE numc10,     " Communication data            END OF empl_data,            empl_data_t TYPE SORTED TABLE OF empl_data WITH UNIQUE KEY empid.      METHODS constructor IMPORTING VALUE(i_empid)   TYPE int4.     METHODS get_data    RETURNING VALUE(rs_result) TYPE empl_data                         RAISING   RESUMABLE(cx_no_data_found).    PRIVATE SECTION.      DATA  emp_id       TYPE int4.      METHODS get_emptyp RETURNING VALUE(r_result) TYPE string                        RAISING   cx_no_data_found.     METHODS get_salary RETURNING VALUE(r_result) TYPE decfloat16                        RAISING   RESUMABLE(cx_no_data_found).     METHODS get_phone  RETURNING VALUE(r_result) TYPE numc10.     METHODS get_emp_id RETURNING VALUE(r_result) TYPE int4.  ENDCLASS.  CLASS lcl_employee IMPLEMENTATION.    METHOD constructor.     me->emp_id = i_empid.   ENDMETHOD.    METHOD get_data.     rs_result = VALUE #( empid  = me->get_emp_id( )                          emptyp = me->get_emptyp( )                          salary = me->get_salary( )                          phone  = me->get_phone( ) ).   ENDMETHOD.    METHOD get_emptyp.     r_result = SWITCH #( me->get_emp_id( )                 WHEN 1 THEN |Full-Time|                 WHEN 2 THEN |Part-Time|                 WHEN 3 THEN |Contractor|                 WHEN 4 THEN |Casual|                 ELSE THROW cx_no_data_found(                             rel_proc_id = CONV #( me->get_emp_id( ) ) ) ).   ENDMETHOD.    METHOD get_phone.     r_result = SWITCH #( me->get_emptyp( )                 WHEN `Full-Time` THEN |1234567890|                 WHEN `Part-Time` THEN |5678901234|                 WHEN `Casual`    THEN |7890123456|                 ELSE |0399999999| ).   ENDMETHOD.    METHOD get_salary.     r_result = SWITCH #( me->get_emptyp( )                 WHEN `Full-Time` THEN 50000                 WHEN `Part-Time` THEN 25000                 WHEN `Casual`    THEN 5000                 ELSE THROW RESUMABLE cx_no_data_found(                             rel_proc_id = CONV #( me->get_emp_id( ) ) ) ).   ENDMETHOD.    METHOD get_emp_id.     r_result = me->emp_id.   ENDMETHOD.  ENDCLASS.  DATA extract_t TYPE lcl_employee=>empl_data_t. DATA error_t   TYPE string_table.  START-OF-SELECTION.    DATA(all_employees_t) = VALUE int4_table(  ( 1 ) ( 2 ) ( 3 ) ( 4 ) ( 5 ) ).    LOOP AT all_employees_t REFERENCE INTO DATA(dref).     TRY.         INSERT NEW lcl_employee( dref->* )->get_data( ) INTO TABLE extract_t.        CATCH BEFORE UNWIND cx_no_data_found INTO DATA(no_data_error).         IF no_data_error->is_resumable = abap_true.           " Вызванное возобновляемое исключение           RESUME.          CLEANUP INTO DATA(lv_clear).         ELSE.           " Вызванное не возобновляемое исключение           error_t = VALUE #( BASE error_t ( no_data_error->get_text( ) ) ).         ENDIF.      ENDTRY.   ENDLOOP.    cl_demo_output=>new( )->write( extract_t )->write( error_t )->display( ).

Благодаря RESUME в методе получения зарплаты, когда зарплата не была найдена, в таком случае нам надо сообщить об ошибке и добавить запись. Если убрать RESUME то после вызова исключения, запись в таблицу добавленна не будет.

Не обращайте внимание на BEFORE UNWIND, о нём мы поговорим чуть позже.

RETRY

С RETRY вы выходите из блока CATCH и прыгаете обратно в блок TRY структура управления для того, чтобы повторить полный блок TRY. Конечно, вы должны позаботиться о том, чтобы исключение не повторялось снова и снова, иначе вы попадете в бесконечный цикл.

CLASS lcl_main DEFINITION FINAL.   PUBLIC SECTION.     METHODS:       method1,       method2. ENDCLASS. CLASS lcl_main IMPLEMENTATION.   METHOD method1.      TRY.         method2( ).       CATCH BEFORE UNWIND cx_root.         cl_demo_output=>write( 'catching cx_root' ).     ENDTRY.      cl_demo_output=>display( ).   ENDMETHOD.   METHOD method2.     DATA(index) = 0.     TRY.         DATA(result) = 2 / index.       CATCH cx_sy_zerodivide.         cl_demo_output=>write( 'catching cx_sy_zerodivide' ).         index = 1.         cl_demo_output=>write( 'catching retry' ).         RETRY.     ENDTRY.   ENDMETHOD. ENDCLASS.  START-OF-SELECTION.   NEW lcl_main( )->method1( ).

BEFORE UNWIND

Если указано дополнение BEFORE UNWIND, контекст, в котором исключение был вызван, включая все вызванные процедуры и их локальные данные, удаляется только после выхода из CATCH блок. Если добавление не указано, контекст удаляется до выполнения CATCH блока.

  • Если дополнение BEFORE UNWIND указано, оператор RESUME может быть использован в CATCH блоке для обработки возобновляемого исключения, чтобы возобновить обработку после инструкции, которая вызвала исключение. Это единственный случай, когда контекст исключения не удаляется при выходе из CATCH блока.

  • Возобновляемые исключения также могут обрабатываться CATCH блоками без добавления BEFORE UNWIND. В этом случае контекст исключения удаляется перед процессом обработки, и оператор RESUME не может быть указан.

  • Любые [CLEANUP](<https://eduardocopat.github.io/abap-docs/7.40/abapcleanup>) блоки всегда выполняется непосредственно перед удалением их контекста. Если BEFORE UNWIND используется, то после обработки исключений и во всех остальных случаях до обработки исключений.

  • Использование дополнения BEFORE UNWIND для CATCH требуется только тогда, когда заявление [RESUME](<https://eduardocopat.github.io/abap-docs/7.40/abapresume>) используется. Однако это в принципе разрешено во время обработки исключений, если контекст исключения должен быть оценен перед любыми действиями по очистке в CLEANUP блоки. Это имеет смысл, например, при обработке узких мест в ресурсах, если высвобождение ресурсов в CLEANUP блоке изменили бы контекст и, таким образом, произвели бы вычисление, свободные ресурсы в обработчике исключений бессмысленны.


ссылка на оригинал статьи https://habr.com/ru/articles/728588/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *