Special Usages
TRY… CATCH…
在异常处理过程中使用的一些语句
CATCH … INTO …
在INTO 语句中可以直接声明对象,用于查看具体的异常信息,可用的参数/方法可以在对应的异常类中查看
CATCH 语句可以用于捕获多个异常类型,可以直接在 CATCH 后添加多个异常类,也可以添加多个 CATCH 语句
例:
SELECT * FROM spfli INTO TABLE @DATA(lt_data) UP TO 2 ROWS.
TRY .
DATA(lwa_data) = lt_data[ 3 ].
CATCH cx_sy_itab_line_not_found INTO DATA(lo_error).
DATA(lv_text) = lo_error->get_text( ).
ENDTRY.
测试结果:
RETRY
捕获到异常时,在CATCH 语句中对异常进行处理后,使用 RETRY 再次执行 TRY 语句
使用 RETRY 处理异常时,尽量多的添加限制条件,避免导致死循环
例:
DATA(lv_num) = 1.
TRY .
DATA(lv_error) = lv_num / 0.
CATCH cx_sy_zerodivide.
IF lv_num IS NOT INITIAL.
CLEAR lv_num.
RETRY.
ENDIF.
ENDTRY.
测试结果:
RAISE EXCEPTION
在 TRY 语句中,使用 RAISE EXCEPTION 手动抛出异常【使用 RAISE RESUMABLE EXCEPTION 抛出可恢复异常】
例:
DATA(lv_num) = 101.
TRY.
IF abs( lv_num ) > 100.
RAISE EXCEPTION TYPE cx_demo_abs_too_large.
ENDIF.
CATCH cx_demo_abs_too_large INTO DATA(lo_large).
DATA(lv_text) = 'CATCH cx_demo_abs_too_large : ' && lo_large->get_text( ).
ENDTRY.
测试结果:
CLEANUP
CLEANUP 语句仅在当前 TRY 语句有异常抛出且无法被当前 CATCH 语句捕获时执行,执行后再将异常传递至上层处理语句
例:
TRY.
TRY.
DATA(lv_div) = 1 / lv_num.
DATA(lv_sqrt) = sqrt( lv_num ).
CATCH cx_sy_zerodivide INTO DATA(lo_zero).
DATA(lv_zero) = 'CATCH cx_sy_zerodivide : ' && lo_zero->get_text( ).
CLEANUP.
DATA(lv_cleanup) = 'CLEANUP'.
ENDTRY.
CATCH cx_sy_arithmetic_error INTO DATA(lo_negative).
DATA(lv_negative) = 'CATCH cx_sy_arithmetic_error : ' && lo_negative->get_text( ).
ENDTRY.
测试结果:
CATCH BEFORE UNWIND
CATCH BEFORE UNWIND 用法与 CATCH 一致,但在使用时,该异常抛出部分的 CLEANUP 代码块将被推迟执行,在 CATCH BEFORE UNWIND 语句执行结束后,才会回到 CLEANUP 语句中继续执行
例:
DATA(lv_num) = 0.
TRY.
TRY.
DATA(lv_div) = 1 / lv_num.
CLEANUP.
lv_num = lv_num + 100.
ENDTRY.
CATCH BEFORE UNWIND cx_sy_zerodivide INTO DATA(lo_zero).
CLEAR lv_num.
DATA(lv_zero) = 'CATCH cx_sy_zerodivide : ' && lo_zero->get_text( ).
ENDTRY.
测试结果:
RESUME
使用 RESUME 处理可恢复异常,使该异常所在的 TRY 语句继续执行
该语句只能在 CATCH BEFORE UNWIND 下使用, 不可恢复的异常使用 RESUME 时会抛运行时错误
检查异常是否可以被恢复:IS_RESUMABLE,该成员变量的类型为 ABAP_BOOL
例:
TRY.
cl_demo_output=>write_data( 1 ).
RAISE RESUMABLE EXCEPTION TYPE cx_sy_conversion_rounding.
cl_demo_output=>write_data( 2 ).
CATCH BEFORE UNWIND cx_sy_conversion_rounding INTO DATA(lo_convert).
cl_demo_output=>write_data( 3 ).
IF lo_convert->is_resumable = abap_true.
RESUME.
cl_demo_output=>write_data( 4 ).
ENDIF.
ENDTRY.
cl_demo_output=>display( ).
测试结果:
Call Method
新语法中,可以不使用 CALL METHOD 关键字,直接用内嵌式的方法传参并获取返回值
调用方法时,可以在内部嵌套调用其他的方法,但是该方法的返回值类型与参数需要保持一致
例:
DATA(go_grid) = NEW cl_gui_alv_grid( i_parent = go_splitter->get_container( row = 1
column = 1 ) ).
Demo Output
使用 CL_DEMO_OUTPUT 内置的方法来展示数据,常用于测试
可以通过 WRITE 方法将需要显示的对象加载到 OUTPUT 界面上,再通过 DISPLAY 方法展示该界面
不同类型的对象可以选择使用对应的 WRITE 方法,如下:
WRITE / WRITE_DATA / WRITE_TEXT / WRITE_HTML / WRITE_XML / WRITE_JSON
在 DISPLAY 的方法中也可以传入相应的对象,实际是将 WRITE_XXX 以及 DISPLAY 方法进行了封装,如下:
DISPLAY / DISPLAY_DATA / DISPLAY_TEXT / DISPLAY_HTML / DISPLAY_XML / DISPLAY_JSON
在展示数据时,可以选择添加一些辅助性的内容:
使用 BEGIN_SECTION / NEXT_SECTION / END_SECTION 添加标题,划分章节
使用 LINE 添加分割线
例:
SELECT * FROM makt INTO TABLE @DATA(lt_table) UP TO 2 ROWS.
DATA(lwa_data) = lt_table[ 1 ].
DATA(lv_maktx) = lt_table[ 1 ]-maktx.
cl_demo_output=>begin_section( '---Display Table---' ).
cl_demo_output=>write_data( lt_table ).
cl_demo_output=>line( ).
cl_demo_output=>next_section( '---Display Work Area---' ).
cl_demo_output=>write_data( lwa_data ).
cl_demo_output=>line( ).
cl_demo_output=>next_section( '---Display Field---' ).
cl_demo_output=>write_data( lv_maktx ).
cl_demo_output=>end_section( ).
cl_demo_output=>display( ).
测试结果:
DATA(OUT) = CL_DEMO_OUTPUT=>NEW( ).
OUT->WRITE( ITAB ).
OUT->WRITE( RESULT ).
OUT->DISPLAY( ).
Demo Input
使用 CL_DEMO_INPUT 内置的方法来展示数据,常用于测试
与OUTPUT类似,INPUT使用ADD_FIELD加载字段到界面,并使用REQUEST调出该界面
ADD_FIELD:默认将字段名作为文本显示,text可以指定字段文本,as_checkbox用来设置字段以复选框格式显示
REQUEST:可以直接加载字段并显示,参数与ADD_FIELD一致,如下右图
ADD_TEXT:添加文本内容
ADD_LINE:添加空行
例:
DATA: lv_int TYPE i VALUE 1,
lv_char1 TYPE char1 VALUE 'X'.
cl_demo_input=>add_text( 'Please input the fields below:' ).
cl_demo_input=>add_field( EXPORTING text = 'Checkbox'
as_checkbox = 'X'
CHANGING field = lv_char1 ).
cl_demo_input=>add_line( ).
cl_demo_input=>add_field( CHANGING field = lv_int ).
cl_demo_input=>request( ).
cl_demo_input=>add_text( 'Please input the fields below:' ).
cl_demo_input=>request( CHANGING field = lv_int ).
测试结果:
Fixed point arithmetic
在创建程序时,需要勾选 Fixed point arithmetic,否则会影响部分新语法的使用
正常情况下,该选项默认为选中状态,作用是设置该程序中所有的计算都使用定点计算
在不勾选该选项时,部分新语法,例如下图中 OPEN SQL 的一些使用方式将不会被支持(尤其是在部分增强出口里)
使用非定点运算时,无论定义了多少位小数,在赋值、比较和计算中使用压缩型数据 (ABAP/4类型P、字典类型CURR、DEC或QUAN)时,它们都将被视为整数,算术计算的中间结果也将四舍五入到整数,只有在输出该数据时,才会考虑该小数位个数
例:
DATA:lv_result_d0 TYPE p DECIMALS 0,
lv_div TYPE p DECIMALS 1 VALUE '6.8',
lv_result_d1 TYPE p DECIMALS 1,
lv_result_div TYPE p DECIMALS 1.
lv_result_d0 = 100 / 2.
lv_result_d1 = 100 / 2.
lv_result_div = 100 / lv_div.
测试结果:
左图是没有勾选 Fixed point arithmetic 选项时的执行结果,而右图为勾选状态下的结果
上例中,LV_RESULT_D0 没有小数位,所以结果为50;
LV_RESULT_D1有一位小数,因此结果变为 5.0;
LV_DIV 会被视为整数 68 并用于计算,100 / 68 结果为 1.47,四舍五入后得到 1,LV_RESULT_DIV有一位小数,则结果为 0.1