!--a11y-->

例外の発生は、一般にエラー状況を表示するために使用されます。例外のハンドラは、発生したエラーの修正および代替ソリューションの検索を試行するか、それができない場合は少なくとも影響を受けたコンテキストを整合性がとれた状態にして、その後エラーを転送する必要があります。コール階層に例外のハンドラが含まれない場合は、プログラムは実行時エラーによって終了されます。例外はプログラムコールによっては処理できないため、実行時エラーを防ぐために、プログラムそのもので発生する可能性のある例外をすべて処理する必要があります。この規則は、例外が簡単に ( 外部の) 呼出元に伝播するプロシージャ内のコーディングには適用されません。
クラスベースの例外は以下の制御構造で処理されます。
TRY.
... " TRY block (application coding)
CATCH cx_... cx_... ...
... " CATCH block (exception handler)
CATCH cx_... cx_... ...
... " CATCH block (exception handler)
...
CLEANUP.
... " CLEANUP block (cleanup context)
ENDTRY.
TRY 命令は ENDTRY で終了する制御構造を開きます。ここでは 3 つの命令ブロックを、指定された順序で一覧表示することができます ( これは必須ではありません) 。
...
1.
例外の発生が可能な TRY
ブロック。
この例外ブロックは、TRY
命令および CATCH
命令の間にあるすべての命令で構成されます。
2.
例外をキャッチするための 1
つまたは複数のCATCH
ブロック。
これらの例外ブロックは CATCH
で開始され、追加の CATCH
、CLEANUP
、または ENDTRY
で終了されます。
3.
例外がキャッチされた後のクリーンアップ作業のための CLEANUP
ブロック。
この命令ブロックは CLEANUP
で開始され、ENDTRY
で終了されます。TRY-ENDTRY
構造では、この位置に 2
つ以上の CLEANUP
ブロックが含まれないようにする必要があります。
TRY ブロックには、処理対象の例外のアプリケーションコーディングが含まれます。この命令ブロックは、順番に処理されます。プロシージャまたは他の ABAP プログラムの追加の制御構造および呼出を含めることができます。
TRY ブロックまたはそこで呼び出されたプロシージャで例外が発生した場合、同じ TRY-ENDTRY 構造の CATCH 命令が検索されることによってシステムが起動します。その後、イベントを処理する、囲まれている任意の TRY-ENDTRY 構造内で CATCH 命令がくまなく検索されます。このハンドラが呼び出されることがあります。TRY-ENDTRY 構造がプロシージャに含まれているのに、ハンドラが見つからない場合は、例外は呼出元に伝播されます ( 例外の伝播も参照) 。例外は、ローカルデータ領域( イベントブロック、ダイアログモジュール) なしではどの処理ブロックでも伝播されません。ハンドラが欠落している場合は、ただちに実行時エラーが発生します。
TRY ブロックで例外が発生しない場合は、ブロックが完了した後、ENDTRY の直後にプログラムの実行は継続されます。
CATCH ブロックには、特定の例外が同じ TRY-ENDTRY 構造の TRY ブロックで発生した際に実行される例外ハンドラが含まれます。TRY-ENDTRY 構造には、複数の例外ハンドラを含めることができます。例外ハンドラを導入する構文は以下のとおりです。
CATCH cx_... cx_...INTO ref.
CATCH の後に任意の数の例外クラスを指定することができます。これにより、指定されたすべての例外クラス およびその従属クラスに対して、例外ハンドラが定義されます。
例外が発生した後、一覧表示された例外ハンドラが指定された順序で検索されます。CATCH 命令に対応する例外クラスまたはスーパークラスのうちの 1 つを含む、最初の例外ハンドラが実行されます。その後、ENDTRY の直後にプログラムの実行が継続されます。その以後の例外ハンドラは考慮されません。このため、TRY-ENDTRY 構造内のさまざまな例外ハンドラの順序は、指定された例外クラスの継承階層にもとづく必要があります。
構文チェックにより、特定の例外 ( 従属クラス) のハンドラは、一般的な例外( スーパークラス) のハンドラの前に表示されるようになります。たとえば、最も一般的な例外クラス CX_ROOT のハンドラは、必ず CLEANUP または ENTRY の前の最後の命令ブロックになります。そうしないと、それ以後ハンドラは検索されなくなります。
INTO オプションを使用すると、参照変数に例外オブジェクトへの参照を配置することができます。これにより、ハンドラで例外オブジェクトの属性にアクセスすることができます。参照変数は例外に適している必要があります。参照変数の静的な型は、例外クラスそのものまたはそのスーパークラスの 1 つであることが必要です。例外クラスは、一般クラス OBJECT ではなく、CX_ROOT または CX_ROOT そのものの下位で使用することをお奨めします。これらのクラスには例外に関するメソッドのみが含まれます。
TRY-ENDTRY 構造で例外のハンドラが見つからない場合、上述のように、囲まれている TRY-ENDTRY 構造内でハンドラがくまなく検索されます。ここでもハンドラが見つからない場合は、例外はプロシージャ呼出元に伝播されます。
各 TRY-ENDTRY 構造に、1 つの CLEAMUP ブロックが定義されます。例外のハンドラが見つからないにもかかわらず、例外が囲まれている TRY-ENDTRY 構造で処理されるか呼出元に伝播されると、ブロックは TRY-ENDTRY 構造が終了する前に実行されます。
CLEANUP ブロックでは、TRY ブロックのコンテキストでクリーンアップ作業を実行することができます。たとえば、オブジェクトは一般に整合性のとれた状態にされなければならず、そうでない場合、外部ハンドラがアクセス権を持たなくなった外部リソースは解放しなければなりません。TRY-ENDTRY 構造のネストおよび例外の伝播の可能性は、例外が実際に処理される前に、複数の CLEANUP ブロックが実行されることを意味します。
CLEANUP ブロックの唯一の目的はコンテキストの整合性を復元することであるため、このブロックは正常な方法、すなわち最後の命令に達した後でしか終了できません。このため、制御フローを変更するすべての命令、すなわち CLEANUP ブロックを終了させて同じプログラムの処理ブロックの開始させるすべての命令は禁止されています。これは RETURN 、STOP などの命令に適用されます。同じ理由により、CLEANUP ブロック内で発生するすべての例外も、ここで処理される必要があります。ただし、システムが CLEANUP ブロックに戻る場合は、プログラム全体の終了 (LEAVE PROGRAM) 、またはプロシージャ、プログラム、および画面順序の呼出が可能です。実行時環境では常に CLEANUP ブロックが不法に終了されたことが認識され、実行時エラーが生成されます。

report DEMO_HANDLE_EXCEPTIONS.
parameters NUMBER type I.
data RESULT type P decimals 2.
data OREF type ref to CX_ROOT.
data TEXT type STRING.
start-of-selection.
write: / 'Testing division and Sqare root with', NUMBER.
uline.
try.
if ABS(
NUMBER ) > 100.
raise
exception type CX_DEMO_ABS_TOO_LARGE.
endif.
try.
RESULT
= 1 / NUMBER.
write: /
'Result of division:', RESULT.
RESULT =
SQRT( NUMBER ).
write: /
'Result of square root:', RESULT.
catch
CX_SY_ZERODIVIDE into OREF.
TEXT =
OREF->GET_TEXT( ).
cleanup.
clear
RESULT.
endtry.
catch
CX_SY_ARITHMETIC_ERROR into OREF.
TEXT =
OREF->GET_TEXT( ).
catch
CX_ROOT into OREF.
TEXT =
OREF->GET_TEXT( ).
endtry.
if not TEXT
is initial.
write /
TEXT.
endif.
write: /
'Final result:', RESULT.
この例では、TRY-ENDTRY 構造は、異なる TRY-ENDTRY 構造の TRY ブロックにネストされています。例では、以下の 4 つのシナリオが示されています。
スーパークラスを処理することにより、例外をキャッチ
NUMBER が 100 より大きい場合は、ABAP ワークベンチの例外ビルダ でユーザ定義された例外 CX_DEMO_ABS_TOO_LARGE が、外部の TRY-ENDTRY 構造の TRY ブロックに生成されます。この例外は最も一般的な例外 CX_ROOT の従属クラスであり、同じ TRY-ENDTRY 構造の 2 番めの CATCH ブロックによって処理されます。
適したクラスを処理することにより、例外をキャッチ
NUMBER がゼロの場合は、内部の TRY-ENDTRY 構造の TRY ブロックでの除算の結果として、システムで事前定義された例外 CX_SY_ZERODIVIDE が生成され、同じ TRY-ENDTRY 構造の対応する CATCH ブロックで処理されます。
例外をキャッチする前に CLEANUP ブロックを実行
NUMBER が負の数値の場合、システムで事前定義された例外 CX_SY_ARG_OUT_OF_DOMAIN が、SQRT 機能を使用して内部の TRY-ENDTRY 構造の TRY ブロックに生成されます。内部の TRY-ENDTRY 構造ではこの例外に対してハンドラは定義されておらず、外部の TRY-ENDTRY 構造で定義されているため、内部の TRY-ENDTRY 構造の CLEANUP ブロックが実行されます。CX_SY_ARG_OUT_OF_DOMAIN は CX_SY_ARITHMETIC_ERROR の従属クラスであるため、その後例外は、外部の TRY-ENDTRY 構造の最初の CATCH ブロックで処理されます。
例外なし
他のすべてのケースにおいては、例外は生成されず、両方の TRY-ENDTRY 構造の TRY ブロックがすべて処理されます。
例のすべての CATCH 命令において、対応する例外オブジェクトへのオブジェクト参照は、OREF 参照変数に格納されます。OREF を使用すると、個々のハンドラは個々の例外オブジェクトの例外テキストにアクセスして、これらを TEXT 文字列変数に格納します。