例外クラスの定義と処理

例外クラスの使用

Objective

After completing this lesson, you will be able to 例外クラスを使用します。

例外処理

このコースの前半では、TRY、CATCH、および ENDTRY 命令を使用したエラー処理について確認しました。TRY 文の後に、エラーの原因となる可能性のある文が出力されます。エラーが発生すると、CATCH 命令にジャンプしてその内容が処理されます。どのような場合でも、このメソッドは ENDTRY 命令の後の処理を実行します。

TRY…ENDTRY ブロックには、複数の CATCH 命令を含めることができます。これにより、さまざまな例外を異なる方法で処理することができます。

1 つの CATCH 命令に複数の例外を一覧表示することができます。この例では、cx_sy_arithmetic_error または cx_sy_zerodivide がトリガされると、同じ CATCH ブロックが処理されます。

CATCH 命令でクラスを一覧表示すると、そのクラスまたはそのサブクラスの 1 つで例外がトリガされると、対応するブロックが処理されます。この例では、cx_sy_arithmetic_error は cx_sy_arithmetic_overflow と cx_sy_zerodivide の両方のスーパークラスです。いずれかのサブクラスのタイプの例外が発生すると、ブロックが処理されます。

すべての例外クラスは、最上位のスーパークラスがクラス cx_root である継承階層の一部です。すでに説明したように、CATCH 命令でスーパークラスを使用すると、そのサブクラスのいずれかのタイプを持つ例外がトリガされると、スーパークラスにジャンプします。すべての例外クラスは cx_root のサブクラスであるため、例外を捕捉するには CATCH cx_root 命令で十分です。

CATCH 命令の順序

CATCH 命令を記述するときは、最も具体的なクラス (複数可) を最初に配置し、最も一般的なクラスを最後に配置する必要があります。スーパークラスをそのサブクラスの 1 つ上に置くと、構文エラーが発生します。これは、特定の CATCH ブロックがより一般的なブロックによってオーバーシャドウされているため、処理できなかったためです。

INTO オプション

各例外は、オブジェクトによって表されます。このオブジェクトは、参照変数に配置して使用することができます。たとえば、この例に示すように、get_text( ) メソッドを使用して例外クラスからエラーテキストを取得することができます。

CATCH 命令でインライン宣言を使用して、参照変数が正しいデータ型で宣言されるようにすることができます。

例外オブジェクトを使用する最も一般的な方法は、get_text( ) メソッドを呼び出すことです。ただし、例外オブジェクトは、エラーの処理に役立つ他の属性とメソッドを持つことができます。

例外クラスには、何がうまくいかなかったかをより正確に説明する属性を含めることができます。これらの属性は、多くの場合、メッセージのプレースホルダを入力するために使用されます。例外クラスのパブリックセクションで、属性を適切な名称およびタイプで定義します。

例外が発生したときに属性を入力するには、例外クラスのコンストラクタの対応するインポートパラメータが必要です。このインポートパラメータは、クイックフィックスを使用して生成することができます。メソッド名 constructor にカーソルを合わせ、Ctrl + 1 を押します。クイックフィックスコンストラクタを再生成を選択します。

例外の伝播

メソッドは、呼出チェーンに沿って例外を伝播することができます。CATCH 命令を使用して例外を処理するのではなく、メソッドの定義に RAISING 句を含めます。これは、メソッドの呼出元に例外を渡すことができることを示します。

例外が呼出チェーンのどこにも捕捉されない場合は、実行時エラーが発生します。

属性 previous

場合によっては、呼び出しチェーン内でメソッドが例外を捕捉し、応答として、独自の呼び出し元が捕捉するために別の例外を発生させます。これは、たとえば、アプリケーションが処理するには技術指向すぎる例外がフレームワークで発生する場合に発生することがあります。独自の例外をトリガするメソッドは、最初の例外を渡すことができます。これは、例外クラスの previous 属性を使用して行うことができます。

例外を発生させる場合、例外クラスのインスタンスをインポートパラメータ previous に渡すことができます。これにより、例外オブジェクトが新規例外に添付されます。2 番目の例外を捕捉するメソッドは、パブリック読込専用属性 previous を使用して最初の例外オブジェクトにアクセスできます。

previous はスーパークラス cx_root に実装されるため、すべての例外クラスで使用することができます。

試してみる: 例外クラス

  1. インタフェース IF_OO_ADT_CLASSRUN を実装する新しいクラスを登録します。
  2. 以下のコードスニペットをメソッド if_oo_adt_classrun~main( ) の実装部分にコピーします。
    Code Snippet
    12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
    DATA number1 TYPE i VALUE 2000000000. DATA number2 TYPE p LENGTH 2 DECIMALS 1 VALUE '0.5'. DATA result TYPE i. TRY. result = number1 / number2. CATCH cx_sy_arithmetic_overflow. out->write( 'Arithmetic Overflow' ). CATCH cx_sy_zerodivide. out->write( 'Division by zero' ). ENDTRY. number2 = 0. TRY. result = number1 / number2. CATCH cx_sy_arithmetic_overflow. out->write( 'Arithmetic Overflow' ). CATCH cx_sy_zerodivide. out->write( 'Division by zero' ). ENDTRY. TRY. result = number1 / number2. CATCH cx_sy_arithmetic_overflow cx_sy_zerodivide. out->write( 'Arithmetic overflow or division by zero' ). ENDTRY. TRY. result = number1 / number2. CATCH cx_sy_arithmetic_error. out->write( 'Caught both exceptions using their common superclass' ). ENDTRY. TRY. result = number1 / number2. CATCH cx_root. out->write( 'Caught any exception using CX_ROOT' ). ENDTRY. TRY. result = number1 / number2. CATCH cx_root into data(Exception). out->write( 'Used INTO to intercept the exception object' ). out->write( 'The get_Text( ) method returns the following error text: ' ). out->write( Exception->get_text( ) ). ENDTRY.
  3. Ctrl + F3 を使用してクラスを有効化します。
  4. コーディングを操作して、理解します。

例外オブジェクトの使用

例外オブジェクト、つまり例外クラスのインスタンスにアクセスすることで、コードを改善します。コンストラクタパラメータを使用して、例外オブジェクトの属性値を設定します。

テンプレート:

  • /LRN/CL_S4D401_OOS_FACTORY (グローバルクラス)

ソリューション:

  • /LRN/CL_S4D401_EXS_HANDLING (グローバルクラス)

タスク 1: テンプレートのコピー (オプション)

テンプレートクラス /LRN/CL_S4D401_OOS_FACTORY をコピーします。前の演習問題を完了した場合は、このタスクをスキップし、クラス ZCL_##_SOLUTION の編集を続行することができます。

ステップ

  1. クラス /LRN/CL_S4D401_OOS_FACTORY を各自のパッケージのクラスにコピーします (推奨名: ZCL_##_SOLUTION、## はグループ番号)。

    1. Project Explorer で、クラス /LRN/CL_S4D401_OOS_FACTORY を右クリックしてコンテキストメニューを開きます。

    2. コンテキストメニューから Duplicate.... を選択します。

    3. Package 項目にパッケージの名称を入力します。Name 項目に、ZCL_##_SOLUTION (## はグループ番号) と入力します。

    4. Next を選択します。

    5. 移送依頼を確認し、Finish を選択します。

  2. コピーを有効化します。

    1. Ctrl + F3 を押してクラスを有効化します。

タスク 2: 例外オブジェクトへのアクセス

グローバルクラスで、メソッド IF_OO_ADT_CLASSRUN~MAIN の実装を調整します。ファクトリメソッド GET_INSTANCE の呼出時に例外処理を拡張します。両方の CATCH ブロックで、例外オブジェクトへの参照を受け取り、例外テキストを抽出します。コンソール出力のリテラルテキストを例外テキストに置き換えます。

ステップ

  1. グローバルクラスのメソッド IF_OO_ADT_CLASSRUN~MAIN の実装にナビゲートします。

    1. グローバルクラスを開き、グローバルクラスタブに切り替えます。

  2. 最初の CATCH 命令で、参照変数が例外オブジェクト (例外クラス CX_ABAP_INVALID_VALUE のインスタンス) をポイントするようにします (変数の推奨名: exc_inv)。

    ヒント

    インライン宣言を使用して、参照変数を正しいデータ型で宣言することができます。
    1. コードを以下のように調整します。

      ABAP
      1
      CATCH cx_abap_invalid_value INTO DATA(exc_inv).
    2. 変数 exc_inv のタイプを照会するには、カーソルを exc_inv に置いて F2 を押します。

  3. CX_ABAP_INVALID_VALUE CATCH ブロックで、メソッド out->write の呼出をコメントアウトします。例外オブジェクトから例外テキストを取得し、それをメソッド out->write の新しい呼出で使用します。

    1. コードを以下のように調整します。

      ABAP
      123
      CATCH cx_abap_invalid_value INTO DATA(exc_inv). * out->write( |Carrier { c_carrier_id } does not exist| ). out->write( exc_inv->get_text( ) ).
  4. 2 番目の CATCH 命令および CATCH ブロックでも同じ操作を行います (参照変数の推奨名: exc_auth)。

    1. コードを以下のように調整します。

      ABAP
      123
      CATCH cx_abap_auth_check_exception INTO DATA(exc_auth). * out->write( |No authorization to display carrier { c_carrier_id }| ). out->write( exc_auth->get_text( ) ).
  5. コードを有効化してテストします。定数 c_carrier_id の値を調整して、さまざまな例外を発生させます。

    1. Ctrl + F3 を押してコードを有効化します。

    2. F9 を押して、コードをコンソールアプリとして実行します。

    3. 定数 c_carrier_id の値を XX に設定して、無効な値の例外を発生させます。

    4. 定数 c_carrier_id の値を UA に設定して、権限不足の例外を発生させます。

タスク 3: 例外グループの処理

ローカルテストクラス LTCL_FIND_FLIGHTS で、メソッド CLASS_SETUP の実装を調整します。ファクトリメソッド GET_INSTANCE の呼出時に、可能性のあるすべての例外を 1 つの CATCH ブロックで処理します。例外の場合、一般エラーメッセージの "lcl_carrier をインスタンス化できません"の代わりに、例外オブジェクトから例外テキストとともに失敗メソッドを指定します。

ステップ

  1. ローカルテストクラス LTCL_FIND_FLIGHTS のメソッド CLASS_SETUP の実装にナビゲートします。

    1. テストクラスタブに切り替えます。

    2. ステートメント METHOD class_setup までスクロールします。

  2. メソッド GET_INSTANCE の呼出後、例外処理を調整します。例外クラス CX_ABAP_INVALID_VALUE の捕捉ブロックにコメントを付け、例外クラス CX_ABAP_AUTH_CHECK_EXCEPTIONCX_ROOT に置き換えます。

    1. コードを以下のように調整します。

      ABAP
      1234567
      TRY. the_carrier = lcl_carrier=>get_instance( i_carrier_id = some_flight_data-carrier_id ). * CATCH cx_abap_invalid_value. * cl_abap_unit_assert=>fail( `Unable to instantiate lcl_carrier` ). CATCH cx_root. cl_abap_unit_assert=>fail( `Unable to instantiate lcl_carrier` ). ENDTRY.
  3. インライン宣言参照変数を使用して CATCH 文に INTO 句を追加します (変数の推奨名: exc_root)。

    1. コードを以下のように調整します。

      ABAP
      1
      CATCH cx_root INTO DATA(exc_root).
    2. 変数 exc_root のタイプを表示するには、カーソルを exc_root に置いて F2 を押します。

  4. CX_ROOT CATCH ブロックで、例外テキストをメソッド CL_ABAP_UNIT_ASSERT=>fail の入力として使用します。

    1. コードを以下のように調整します。

      ABAP
      12
      CATCH cx_root INTO DATA(exc_root). cl_abap_unit_assert=>fail( exc_root->get_text( ) ).
  5. コードを有効化します。

    1. Ctrl + F3 を押します。

タスク 4: 例外オブジェクトの属性設定

ファクトリメソッド GET_INSTANCE で例外の発生を調整します。例外 CX_ABAP_INVALID_VALUE を発生させる場合は、適切なコンストラクタパラメータを使用して、無効な航空会社 ID を例外テキストに含めます。例外 CX_ABAP_AUTH_CHECK_EXCEPTION を発生させる場合は、適切なコンストラクタパラメータを使用して、より適切な例外テキストを選択します。

ステップ

  1. ローカルクラス LCL_CARRIER のメソッド GET_INSTANCE の実装にナビゲートします。

    1. たとえば、IF_OO_ADT_CLASSRUN~MAIN メソッドで、get_instance にカーソルを置き、F3 を押します。

  2. 例外クラス CX_ABAP_INVALID_VALUECONSTRUCTOR メソッドの署名を分析します。

    1. RAISE EXCEPTION 命令で、CX_ABAP_INVALID_VALUE にカーソルを置き、F2 を押して例外クラスの ABAP エレメント情報を表示します。

    2. ダイアログウィンドウで、コンストラクタを選択して CONSTRUCTOR メソッドのエレメント情報を表示します。

  3. 例外クラス CX_ABAP_INVALID_VALUE の RAISE EXCEPTION 命令を調整します。コンストラクタパラメータ値に無効な航空会社 ID を指定します。

    注記

    valuei_carrier_id は同じデータ型を持たないため、データ型変換を実行する必要があります。
    1. コードを以下のように調整します。

      ABAP
      123
      RAISE EXCEPTION TYPE cx_abap_invalid_value EXPORTING value = CONV #( i_carrier_id ).
  4. 例外クラス CX_ABAP_AUTH_CHECK_EXCEPTION の RAISE EXCEPTION 命令を調整します。コンストラクタパラメータ textid に、その例外クラスの public 定数 missing_authorization を指定します。

    1. コードを以下のように調整します。

      ABAP
      1234
      RAISE EXCEPTION TYPE cx_abap_auth_check_exception EXPORTING textid = cx_abap_auth_check_exception=>missing_authorization.
  5. コードを有効化してテストします。定数 c_carrier_id の値を調整して、さまざまな例外を発生させます。

    1. Ctrl + F3 を押してコードを有効化します。

    2. F9 を押して、コードをコンソールアプリとして実行します。

    3. 定数 c_carrier_id の値を XX に設定して、無効な値の例外を発生させます。

    4. 定数 c_carrier_id の値を UA に設定して、権限不足の例外を発生させます。