!--a11y-->

プロシージャ ( メソッド、汎用モジュール、サブルーチン) で発生するクラスベースの例外は、必ずしもここで処理する必要はありません。これらは、プロシージャの呼出元に伝播することができます。呼出元がプロシージャで、呼出が TRY ブロックで行われる場合は、呼出元は例外を処理するか、その呼出元に伝播することができます。
例外を伝播できる最上位レベルは、ローカルデータ領域なしの処理ブロック、すなわちイベントブロックまたはダイアログモジュールです。呼び出されたプロシージャから転送された例外、および個々のコーディングで発生した例外の両方とも、ここで処理される必要があります。ここで処理されない場合、実行時エラーが発生します。
クラスの静的コンストラクタは一般に例外を伝播できません。クラスのユーザは、それが最初のユーザかどうか、静的コンストラクタによって伝播された任意の例外を処理すべきかどうかわからないためです。
同様に、イベントハンドラメソッドも例外を伝播できません。これはイベントのコンセプトに反するためです。イベントのハンドラは、イベントの発生時に実行時環境によって間接的に呼び出されます。イベントのハンドラはイベントトリガとはまったく別個であるため、トリガに例外を転送できません。逆の場合も同様で、イベントトリガはどのハンドラがイベントに対応するかわからないため、ハンドラの例外は処理できません。
例外は、プログラムの内部セッションだけに " 生存" している一時的なオブジェクトによって表されるため、例外は SUBMIT ... AND RETURN または CALL TRANSACTION で呼び出されたプログラムの呼出元には伝播できません。
プロシージャから例外を伝播するには、一般に RAISING オプションを使用してプロシージャのインタフェースを定義する必要があります ( 静的コンストラクタおよびイベントハンドラを除く) 。これにより、プロシージャの呼出元はプロシージャでどの例外が発生するかを認識して、例外を処理したり RASING オプションを使用して転送したりすることができます。
RAISING 句では、プロシージャで例外を生成するすべての例外クラスのクラスを数えて合計を出す必要があります ( 厳密に言えば、これは宣言を必要とする例外にのみあてはまります) 。( 追加情報については、以下を参照してください。) ここでは、例外のグループを統合するためにスーパークラスを指定することもできます。ただし、最も一般的なスーパークラス CX_ROOT 、およびその直接従属クラス CX_NO_CHECK は指定できません ( 下記参照) 。例外の処理での CATCH ブロックの順序は、例外クラスの継承階層によって決定されるため、RAISING 句の例外クラスもこの順序で指定する必要があります。これにより、プロシージャの呼出元は、プロシージャインタフェースの知識にもとづくだけで、正しい順序で CATCH ブロックを表示することができます。クラスビルダの例外クラスを参照する必要はありません。
これは使用可能なプロシージャに対して、以下のように処理されます。
RAISING オプションは、メソッドの宣言で指定されます。
METHODS meth ...RAISING cx_... cx_...
オブジェクトが伝播される例外クラスは、RAISING の後に、上記の順序で指定されます。EXCEPTIONS オプションを持つ従来の例外を同時に指定することはできません。
RAISING オプションを、グローバルクラスのメソッドで直接指定することはできません。代わりに、オブジェクトが伝播される例外クラスを、クラスビルダのメソッドの例外テーブルに入力する必要があります。クラスビルダでは指定された例外が上記の順序でソートされ、対応する RAISING 句が生成されます。
そのためには、クラスビルダの例外テーブルの例外クラスチェックボックスをオンにしておく必要があります。オンにしないと、クラスビルダは従来の例外として入力された例外を参照して、対応するEXCEPTIONS 句を生成します。クラスビルダでは、例外クラスと従来の例外を同時に使用することはできません。
宣言を必要とする例外が例外テーブルで定義されていない場合は ( 以下参照) 、RAISING 句が不完全であるため、構文チェックでエラーが報告されます。
汎用モジュールの例外は、汎用モジュールビルダで指定されたときに、クラスビルダのグローバルメソッドと同じ方法で伝播されます。汎用モジュールビルダには該当するタブページがあり、クラスビルダにおけるメソッドの例外テーブルと同じ方法で機能します。クラスベースの例外を伝播するには、ここで該当するチェックボックスもオンにする必要があります。オンにしないと、従来の例外が宣言されます。
サブルーチンを使用すると、サブルーチンの定義に RAISING オプションが指定されます。
FORM form ...RAISING cx_... cx_...
オブジェクトが伝播される例外クラスは、RAISING の後に指定されます。クラスベースの例外は、サブルーチンのインタフェースに一覧表示できる唯一の例外です。
プロシージャで発生する例外は、一般にここで処理されるか、またはプロシージャのインタフェースを介して RAISING オプションで上位レベルに転送されます。これは構文チェック ( メソッドの場合) または拡張プログラムチェック ( 汎用モジュールまたはサブルーチンの場合) でサポートされます。たとえば、以下のサブルーチンの構文は正しくありません。
form TEST.
raise
exception type CX_DEMO_CONSTRUCTOR.
endform.
エラーは、サブルーチンで例外を処理することによって削除するか、
form TEST.
try.
raise
exception type CX_DEMO_CONSTRUCTOR.
catch
CX_DEMO_CONSTRUCTOR.
...
endtry.
endform.
または、RAISING 句を介して例外を伝播します。
form TEST raising CX_DEMO_CONSTRUCTOR.
raise
exception type CX_DEMO_CONSTRUCTOR.
endform.
構文をチェックして、その結果としてインタフェースの宣言を使用して例外を処理または転送するプロシージャは、多くのアプリケーション固有なエラー状況に適しています。ただし、このプロシージャが適切ではない例外状況もあります。たとえば以下のような場合です。
キ 発生するが、処理または宣言する必要のない例外。
ユーザはプログラムロジックによって例外が発生しないようにすることができるため、この種類の例外を処理または明示的に転送することを義務づける必要はありません。
キ リソースボトルネック
すべての例外を失敗せずに処理または宣言するには、これらの例外をほとんどすべてのインタフェースで指定しなければなりません。これはプログラムを " 堅固" にするというよりは、むしろ単に読みにくくします。
この問題に対処するために、3 つの異なるタイプの例外クラスが導入されています。
1. 処理または伝播すべき宣言を必要とする例外。これは以前に説明した標準ケースです。
2. 必要に応じてインタフェースで宣言することのできる例外。
3. インタフェースで宣言すべきではない例外。
これはスーパークラス CX_ROOT の 3 つの直接従属クラスによって有効化されます。
...
1. 宣言をする必要のある例外のための CX_STATIC_CHECK
2. 宣言する必要のない例外のための CX_DYNAMIC_CHECK
3. 宣言してはならない例外のための CX_NO_CHECK
これら 3 つのクラスおよびそのスーパークラスCX_ROOT は抽象です。他のすべての例外クラスは、これら 3 つのクラスの従属クラスです。スーパークラスに応じて、例外クラスはそれぞれ 3 つの型のいずれかに属します。
関連する例外クラスは、CX_STATIC_CHECK の従属クラスです。これらのクラスでは、対応する例外は RAISING オプションで処理または明示的に転送される必要があります。これは、構文チェックでチェックされます。構文チェックまたは拡張プログラムチェックによるメッセージ出力が考慮されている場合、宣言を必要とする例外が最上位の呼出レベルで処理されないと、実行時エラーにつながります。
現在のところ、アプリケーションコーディングにおけるエラー状況のユーザ定義された唯一の例外は、CX_STATIC_CHECK の従属クラスです。実行時環境におけるエラー状況には、CX_STATIC_CHECK の従属クラスである事前定義された例外 CX_SY_... はありません。
関連する例外クラスは、CX_DYNAMIC_CHECK の従属クラスです。実行時にこの種類の例外が発生すると、CX_STATIC_CHECK の従属クラスと同じ方法で、RAISING オプションを使って処理または明示的に転送される必要があります。ただし、これは構文チェックではチェック されません。この種類の例外が実行時に処理も転送もされない場合、実行時エラーが発生します。
この種類の例外クラスは、処理または転送を必要としない潜在的なエラー状況には便利です。プログラムロジックがある程度これらを除外するためです。実行時環境におけるエラー状況の事前定義された例外CX_SY_... の多くは、CX_DYNAMIC_CHECK の従属クラスです。このクラスの典型例は CX_SY_ZERODIVIDE です。除算を利用するユーザは、除数を 0 にしないことによって、この例外を回避することができます。実行時環境の事前定義された例外クラスに宣言を要求するのは、実際には不可能です。プロシージャの各 ABAP 命令の潜在的な例外それぞれを処理または伝播する必要があるためです。
CX_DYNAMIC_CHECK カテゴリの例外はインタフェースで宣言する必要がないため、呼び出されたプロシージャは、これらを防止するか処理するかを判断します。呼出元は、この種類の例外を転送できません。
関連する例外クラスは、CX_NO_CHECK の従属クラスです。この種類の例外は処理することができます。処理できない場合は、 自動的に転送されます。RAISING 句には CX_NO_CHECK オプションが暗黙的に含まれています。このクラスとその従属クラスは、指定してはなりません ( する必要もありません) 。このため、ここでは構文チェックでエラーが検出されることはありません。コール階層で処理されないCX_NO_CHECK カテゴリのすべての例外は、自動的に最上位の呼出レベルに割り当てられ、ここでキャッチされない場合は実行時エラーになります。
実行時環境におけるエラー状況の事前定義された例外 CX_SY_... の一部は、CX_NO_CHECK の従属クラスです。この一例として、クラスCX_SY_EXPORT_TO_BUFFER_NO_MEMORY が挙げられます。このクラスは特定のリソースボトルネックを担当しますが、通常は処理されません。プロシージャの呼出元は、プロシージャがCX_NO_CHECK カテゴリの例外を伝播できることを、常に考慮する必要があります。
プロシージャのインタフェースの RAISING 句では、実際にインタフェースを通過する例外だけが、構文で宣言される必要があります。すでにプロシージャで処理された例外は、インタフェースには関係ありません。インタフェースで宣言すべき例外の数は、以下のようにして決定することができます。
キ 明示的な RAISE EXCEPTION またはプロシージャコールの結果としてかどうかに関わらず、プロシージャの TRY コンストラクトの外で発生する、RAISING 句に従って自身でこれらの例外を生成することのできる、CX_STATIC_CHECK カテゴリの例外すべてです。
キ プロシージャの TRY コンストラクト内で発生し、この TRY コンストラクトでは処理されない、CX_STATIC_CHECK カテゴリの例外すべてです。これらは、CATCH によってキャッチされなかったすべての例外、または CATCH ブロック内で発生するすべての例外です。
TRY コンストラクトが TRY または CATCH ブロック内で発生する場合、これらの規則は繰り返し使用されます。
インタフェースの違反とは、プロシージャ内の未処理の例外が、RAISING を使って転送されないことです。上記の説明によれば、CX_NO_CHECK カテゴリの例外は常に暗黙的に伝播されるため、インタフェースの違反はカテゴリ CX_DYNAMIC_CHECK またはCX_STATIC_CHECK の例外に対してのみ発生します。CX_STATIC_CHECK カテゴリの例外の場合、違反は、構文エラーメッセージが無視された場合にのみ発生します。
インタフェースがこの方法で違反された場合、実行時エラーが発生してプログラムは完了されません。代わりに、事前定義されたクラスCX_SY_NO_HANDLER の新しい例外が生成され (CX_NO_CHECK からの継承) 、元の例外の属性 PREVIOUS に参照が定義されます。
CX_SY_NO_HANDLER 例外が発生した場合、これは一般にプロシージャの開発者が CX_DYNAMIC_CHECK カテゴリの例外をローカルで処理し忘れたか、この例外を防ぎ忘れたことを示します。開発者が RAISING 句を拡張し忘れたことを示すわけではありません。この種類の例外のハンドラは、元の例外をキャッチすることはできません。呼出元プロシージャでプログラムエラーを示すことができるだけです。
イベントハンドラおよび静的コンストラクタのインタフェースに明示的な RAISING 句を入れることはできないため、カテゴリ CX_DYNAMIC_CHECK または CX_STATIC_CHECK の未処理例外は一般にCX_SY_NO_HANDLER 例外を招きます。この例外はプログラムで処理することができます。

report DEMO_PROPAGATE_EXCEPTIONS.
class A_CLASS
definition.
public section.
methods FOO importing
P type STRING
raising
CX_DEMO_CONSTRUCTOR
CX_DEMO_ABS_TOO_LARGE.
endclass.
class B_CLASS
definition.
public section.
data A type ref to A_CLASS.
methods BAR raising CX_DEMO_CONSTRUCTOR.
endclass.
data B type ref to B_CLASS.
start-of-selection.
create object B.
try.
B->BAR( ).
catch CX_DEMO_CONSTRUCTOR.
write 'Catching CX_DEMO_CONSTRUCTOR'.
"#EC NOTEXT
endtry.
class A_CLASS
implementation.
method FOO.
raise exception type CX_DEMO_CONSTRUCTOR.
endmethod.
endclass.
class B_CLASS
implementation.
method BAR.
create object A.
try.
...
A->FOO('
SOMETHING')
.
...
catch CX_DEMO_ABS_TOO_LARGE.
...
endtry.
endmethod.
endclass.
この例では、BAR メソッドのRAISING 句のどの例外を宣言する必要があるかが示されています。このメソッドには RAISE EXCEPTION 命令は含まれませんが、FOO メソッドが呼び出されます。インタフェーステキストに従って、FOO メソッドは例外 CX_DEMO_CONSTRUCTOR および CX_DEMO_ABS_TOO_LARGE を提供することができます。CX_DEMO_ABS_TOO_LARGE は CATCH で明示的にキャッチされます。すなわち、CX_DEMO_CONSTRUCTOR だけがインタフェースを通過します。このため、この例外は BAR の RAISING 句で宣言される必要があります。