この文章は Salesforce 機械翻訳システムを使用して翻訳されました。詳細はこちらをご参照ください。
英語に切り替える

カスタム例外の作成

組み込み Apex 例外は発生させることはできず、キャッチのみが可能です。カスタム例外の場合、メソッドでの発生とキャッチが可能です。カスタム例外では、詳細なエラーメッセージを指定したり、catch ブロックでカスタマイズしたエラー処理を行ったりできます。

例外は最上位クラスにできます。つまり、メンバー変数、メソッド、コンストラクタを持ち、インターフェースの実装などが可能です。

カスタム例外クラスを作成するには、組み込み Exception クラスを拡張して、「MyException」や「PurchaseException」のようにクラス名の最後が Exception で終わるように指定します。すべての例外クラスは、システム定義の基本クラス Exception を拡張するため、すべての共通例外メソッドを継承します。

この例では、MyException というカスタム例外を定義します。
1public class MyException extends Exception {}

Java クラスと同様に、ユーザ定義の例外型は継承ツリーを構成し、catch ブロックでこの継承ツリー内の任意のオブジェクトをキャッチできます。次に例を示します。

1public class BaseException extends Exception {}
2public class OtherException extends BaseException {}
3
4try {
5    Integer i;
6    // Your code here
7    if (i < 5) throw new OtherException('This is bad');
8} catch (BaseException e) {  
9    // This catches the OtherException
10}

独自の例外オブジェクトは次のような形で作成し、発生させることができます。

次のような例外を作成できます。
  • 引数のない例外
    1new MyException();
  • エラーメッセージを指定する 1 つの string 型の引数を取る例外
    1new MyException('This is bad');
  • 1つの Exception 型の引数を取るもの。これは原因を特定でき、任意にスタック追跡できます
    1new MyException(e);
  • string 型のエラーメッセージと、任意のスタック追跡に表示される例外チェーンの両方を取る例外
    1new MyException('This is bad', e);

例外と内部例外の再発生

catch ブロックで例外をキャッチしたら、キャッチした例外変数を再発生させることもできます。これは、メソッドが別のメソッドによってコールされていて、コール元のメソッドに例外の処理を委任する場合に役立ちます。キャッチした例外をカスタム例外の内部例外として再発生させ、メインメソッドにカスタム例外種別をキャッチさせることができます。

次の例では、内部例外として例外を再発生させる方法を示します。この例では、My1ExceptionMy2Exception の 2 つのカスタム例外を定義し、両方の情報を使用してスタック追跡を生成します。

1// Define two custom exceptions
2public class My1Exception extends Exception {} 
3public class My2Exception extends Exception {} 
4
5try { 
6    // Throw first exception
7    throw new My1Exception('First exception'); 
8} catch (My1Exception e) { 
9    // Throw second exception with the first 
10    // exception variable as the inner exception
11    throw new My2Exception('Thrown with inner exception', e);
12}

上記のコードを実行した結果のスタック追跡は次のようになります。

15:52:21:073 EXCEPTION_THROWN [7]|My1Exception: First exception

15:52:21:077 EXCEPTION_THROWN [11]|My2Exception: Throw with inner exception

15:52:21:000 FATAL_ERROR AnonymousBlock: line 11, column 1

15:52:21:000 FATAL_ERROR Caused by

15:52:21:000 FATAL_ERROR AnonymousBlock: line 7, column 1

次のセクションの例では、getCause メソッドをコールし、内部例外を使用して例外を処理する方法を示します。

内部例外の例

カスタム例外クラスの作成方法と、例外オブジェクトの構築方法を確認したので、カスタム例外の便利さを示す例を作成して実行してみましょう。

  1. 開発者コンソールで、MerchandiseException という名前のクラスを作成し、次のコードを追加します。
    1public class MerchandiseException extends Exception {}

    この例外クラスは、これから作成する 2 つ目のクラス内で使用します。最後の中括弧で例外クラスの本文を囲みます。例外クラスは空のままにしておき、既存のコードを使用します。このクラスは、組み込み Exception クラスから、getMessage など、すべてのコンストラクタと共通例外メソッドを継承するためです。

  2. 続いて、2 つ目のクラスを MerchandiseUtility という名前で作成します。
    1public class MerchandiseUtility {
    2    public static void mainProcessing() {
    3        try {
    4            insertMerchandise();
    5        } catch(MerchandiseException me) {
    6            System.debug('Message: ' + me.getMessage());    
    7            System.debug('Cause: ' + me.getCause());    
    8            System.debug('Line number: ' + me.getLineNumber());    
    9            System.debug('Stack trace: ' + me.getStackTraceString());    
    10        }
    11    }
    12    
    13    public static void insertMerchandise() {
    14        try {
    15            // Insert merchandise without required fields
    16            Merchandise__c m = new Merchandise__c();
    17            insert m;
    18        } catch(DmlException e) {
    19            // Something happened that prevents the insertion
    20            // of Employee custom objects, so throw a more
    21            // specific exception.
    22            throw new MerchandiseException(
    23                'Merchandise item could not be inserted.', e);
    24        }
    25    }
    26}

    このクラスには、mainProcessing メソッドが含まれ、そのメソッドから insertMerchandise がコールされます。このコール先で、必須項目を指定せずに Merchandise が挿入されるため、例外が発生します。catch ブロックはこの例外をキャッチし、前に作成した新しい例外であるカスタムの MerchandiseException を発生させます。ここでは、2 つの引数 (エラーメッセージ、元の例外オブジェクト) を取る例外のコンストラクタをコールしています。なぜ元の例外を渡すのでしょうか。それは、最初のメソッド mainProcessing で MerchandiseException をキャッチした場合、この例外の本当の原因は MerchandiseException よりも前に発生した元の例外 (内部例外と呼ばれる) であるため、元の例外の情報が役に立つからです。

  3. 理解を深めるために、これらが実際にどう機能するのか見てみましょう。次のコードを実行します。
    1MerchandiseUtility.mainProcessing();
  4. デバッグログ出力を確認します。ログには、次のように表示されます。

    18:12:34:928 USER_DEBUG [6]|DEBUG|Message: Merchandise item could not be inserted.

    18:12:34:929 USER_DEBUG [7]|DEBUG|Cause: System.DmlException: Insert failed. First exception on row 0; first error: REQUIRED_FIELD_MISSING, Required fields are missing: [Description, Price, Total Inventory]: [Description, Price, Total Inventory]

    18:12:34:929 USER_DEBUG [8]|DEBUG|Line number: 22

    18:12:34:930 USER_DEBUG [9]|DEBUG|Stack trace: Class.EmployeeUtilityClass.insertMerchandise: line 22, column 1

    次の点に留意してください。
    • MerchandiseException の原因は DmlException です。必須項目がないことを示す DmlException メッセージも表示されます。
    • スタック追跡は、2 つ目の例外が発生した場所である行 22 です。MerchandiseException の throw ステートメントに対応しています。
      1throw new MerchandiseException('Merchandise item could not be inserted.', e);