繁体   English   中英

在 ABAP 中,Java 的 finally 关键字的等价物是什么?

[英]In ABAP, what is the equivalent of Java's finally keyword?

在 Java 中, finally关键字用于执行代码(与异常一起使用 - try..catch语句),无论是否抛出异常(来源)。

例如:

try {
    // this code might throw an exception
    riskyCall();

    // this code will only run if no exception was thrown above
    mainProgram();
}
finally {
    // this code will always run
    cleanUp();
}

ABAP 中是否有等效的功能? 如果没有,实现相同功能的惯用方式是什么?

我知道 ABAP 有一个CLEANUP关键字,但这似乎只有在抛出异常时才会执行。

我进行了实验,发现以下可能的解决方案。 不幸的是,我想不出没有代码重复的任何解决方案。

METHOD risky_method.
    TRY.
       WRITE 'code before...'.
       IF lv_error_condition = abap_true.
         RAISE EXCEPTION TYPE cx_foo.
       ENDIF.
       WRITE 'Main program...'.
       WRITE 'Cleanup...'.
    CLEANUP.
       WRITE 'Cleanup...'.
    ENDTRY.
ENDMETHOD.

METHOD outer_scope.
    TRY.
        risky_method( ).
    CATCH cx_foo INTO DATA(lx_foo).
        WRITE 'Caught the error!'.
    ENDTRY.
ENDMETHOD.

对于lv_error_condition等于abap_false的情况,执行方法outer_scope的 output 为:

code before... Main program... Cleanup...

对于lv_error_condition等于abap_true的情况,output 是:

code before... Cleanup... Caught the error!

此解决方案的优点是清理始终运行。 它的缺点是需要一些代码重复,因为清理需要编写两次。 如果清理被打包到一个方法中,那么这并不是大量的代码重复。 :-/

ABAP 没有与 Java finally块完全相同的等价物。

有一个TRY ... CLEANUP结构乍一看很相似,但实际上工作方式却大不相同:

METHOD buggy_method.
    TRY.
       WRITE 'code before the error...'.
       RAISE EXCEPTION TYPE cx_foo.
       WRITE 'This line will not get executed.'.
    CLEANUP.
       WRITE 'Cleanup...'.
    ENDTRY.
ENDMETHOD.

" ...on an outer scope...
TRY.
    buggy_method( ).
  CATCH cx_foo INTO DATA(lx_foo).
    WRITE 'Caught the error!'.
ENDTRY.

输出: code before the error... Cleanup... Caught the error!

然而,清理块并不总是*被执行。 它仅在出现异常时执行,并且该异常由同一TRY块中的CATCH处理。 这个想法是将它用于清理,当异常由外部级别的TRY块处理时应该发生。 因此,无论您是否有错误,它对于您想要运行的代码都没有用。 它仅对您要在 try 块无法自行处理的错误的情况下运行的代码有用。


涵盖 Java finally块的一些用例的另一个特性是可恢复异常

" In the class definiton
METHODS buggy_method RAISING RESUMABLE(cx_foo).

" In the class implementation:
METHOD buggy_method.
   WRITE 'code before the error...'.
   RAISE RESUMABLE EXCEPTION TYPE cx_foo.
   WRITE 'code after the error....'.  
ENDMETHOD.

" Somewhere else:
TRY.
    buggy_method( ).
  CATCH BEFORE UNWIND cx_foo INTO DATA(lx_foo).
    WRITE 'Caught the error!'.
    RESUME.
ENDTRY.

输出: code before the error... Caught the error! code after the error.... code before the error... Caught the error! code after the error....

CATCH块末尾的RESUME关键字导致在异常为RAISE RESUMABLE d 后立即继续执行。 因此,当您想确保即使在发生错误的情况下也能执行方法的结尾时,这可能就是您正在寻找的语法。

* 是的,我知道有一些奇特的边缘情况,其中 Java 中的 finally 块没有被执行。 这些在这里无关紧要。

一位同事给了我解决方案。 避免代码重复的技巧,同时仍然允许异常向上传播,是根本不使用CLEANUP关键字,而是:

  1. 在有风险的代码之后,捕获异常CX_ROOT (捕获所有可能的异常,而不仅仅是您期望的异常!)
  2. 运行finally风格的清理代码
  3. 使用IS BOUND查看是否引发异常,如果是,则重新引发

下面是一个例子:

METHOD risky_method.
    TRY.
        WRITE 'code before...'.
        IF lv_error_condition = abap_true.
            RAISE EXCEPTION TYPE cx_foo.
        ENDIF.
        WRITE 'Main program...'.
    CATCH cx_root INTO DATA(lx_root).
    ENDTRY.

    WRITE 'Cleanup...'.

    IF lx_root IS BOUND.
        RAISE lx_root.
    ENDIF.
ENDMETHOD.

METHOD outer_scope.
    TRY.
        risky_method( ).
    CATCH cx_foo INTO DATA(lx_foo).
        WRITE 'Caught the error!'.
    ENDTRY.
ENDMETHOD.

对于lv_error_condition等于abap_false的情况,输出为:

code before... Main program... Cleanup...

对于lv_error_condition等于abap_true的情况,输出为:

code before... Cleanup... Caught the error!

据我所知,根本没有真正的等价物。 例如,如果 ABAP 知道 finally,我会期望这个

TRY.
  RETURN.
FINALLY.
  WRITE / 'Finally'.
ENDTRY.

写出“终于”这个词。 ABAP 程序有很多情况,这肯定是有用的。 最常见的入队之一需要相应的出队,但它也可以是打开/关闭数据集对。

此代码仅输出“尝试”。

尝试。 写/“尝试”。 返回。 WRITE /'返回后'。 清理。 写/'清理'。 结束。 写/'尝试后'。

因此,如果您想运行该清理代码,您将被迫离开您的例程。 或者您编写冗余代码:

  OPEN DATASET iv_file IN TEXT MODE ENCODING UTF-8.
  TRY.
    " ... write something to file
    
    IF do_more IS INITIAL.
       CLOSE DATASET iv_file. 
      RETURN.
    ENDIF.
    
    " ... write more to file ...
    
  CLEANUP.
    CLOSE DATASET iv_file.
  ENDTRY.
  CLOSE DATASET iv_file. 

解决方案通常是以这样的形式编写冗余代码。 但是,假设这会在将数据写入文件时使事物入队和出队。 然后,您可能必须在某些点调用出列和关闭数据集,或者仅在另一点调用关闭数据集。 如果它发生变化,将其放入单独的方法或表单例程中并不好。

我最初来自帕斯卡方面(从学生时代)并最终在那里学习。 它经常被使用,因为基于 pascal 的语言不使用垃圾收集器,当你不再需要它时,你总是必须确保自己释放 object。 所以那里的免费意味着总是运行(当然只要程序仍然运行)。 你宁愿不用担心那里关闭文件之类的事情,因为 <ou 完成后立即释放它,析构函数将在 Free 上调用并为你完成。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM