Newer Version Available
組み込み例外および共通メソッド
Apex には、実行時にエラーが発生した場合にランタイムエンジンが生成する複数の組み込み例外種別が用意されています。前の例では DMLException が使用されていました。その他いくつかの組み込み例外の例を次に説明します。組み込み例外種別の完全なリストは、「Exception クラスおよび組み込み例外」を参照してください。
- DmlException
- insert ステートメントでレコードの必要な項目が欠落している場合など、DML ステートメントに関する問題を示す例外。
- この例では DmlException を使用します。この例の insert DML ステートメントは、必須項目を設定せずに商品品目を挿入しているため、DMLException を発生させます。この例外は、catch ブロックでキャッチされ、System.debug ステートメントを使用して例外メッセージがデバッグログに出力されます。
1try { 2 Merchandise__c m = new Merchandise__c(); 3 insert m; 4} catch(DmlException e) { 5 System.debug('The following exception has occurred: ' + e.getMessage()); 6} - ListException
- 範囲外のインデックスへのアクセスなど、リストに関する問題を示す例外。
- この例では、リストを作成して 1 つの要素を追加します。続いて、2 つの要素にアクセスを試みました。一方の要素はインデックス 0 に存在し、もう一方の要素はインデックス 1 に存在しないために ListException が発生します。この例外は、catch ブロックでキャッチされます。catch ブロックの System.debug ステートメントは、デバッグログに「The following exception has occurred: List index out of bounds: 1」と出力します。
1try { 2 List<Integer> li = new List<Integer>(); 3 li.add(15); 4 // This list contains only one element, 5 // but we're attempting to access the second element 6 // from this zero-based list. 7 Integer i1 = li[0]; 8 Integer i2 = li[1]; // Causes a ListException 9} catch(ListException le) { 10 System.debug('The following exception has occurred: ' + le.getMessage()); 11} - NullPointerException
- null 変数の参照解決に関する問題を示す例外。
- この例では、s という名前の String 変数を作成しますが、この変数は値で初期化されていないため null です。null 変数に対して contains メソッドをコールすると、NullPointerException が発生します。この例外は、catch ブロックでキャッチされ、デバッグログには「The following exception has occurred: Attempt to de-reference a null object」と出力されます。
1try { 2 String s; 3 Boolean b = s.contains('abc'); // Causes a NullPointerException 4} catch(NullPointerException npe) { 5 System.debug('The following exception has occurred: ' + npe.getMessage()); 6} - QueryException
- sObject の単一変数に対する、レコードを返さない、または複数のレコードを返すクエリの割り当てなど、SOQL クエリに関する問題を示す例外。
- この例の 2 つ目の SOQL クエリでは、QueryException が発生します。この例では、クエリの戻り値に Merchandise オブジェクトを割り当てます。クエリでの LIMIT 1 の使用方法を見てください。ここでは、データベースから返されるオブジェクトは 1 つ以下であるため、割り当てることができるのは 1 つのオブジェクトであり、リストではありません。ただし、この場合、XYZ という名前の Merchandise はないため、何も返されず、戻り値を 1 つのオブジェクトに割り当てようとすると QueryException が発生します。例外は catch ブロックでキャッチされ、デバッグログには「The following exception has occurred: List has no rows for assignment to SObject」と表示されます。
1try { 2 // This statement doesn't cause an exception, even though 3 // we don't have a merchandise with name='XYZ'. 4 // The list will just be empty. 5 List<Merchandise__c> lm = [SELECT Name FROM Merchandise__c WHERE Name = 'XYZ']; 6 // lm.size() is 0 7 System.debug(lm.size()); 8 9 // However, this statement causes a QueryException because 10 // we're assiging the return value to a Merchandise__c object 11 // but no Merchandise is returned. 12 Merchandise__c m = [SELECT Name FROM Merchandise__c WHERE Name = 'XYZ' LIMIT 1]; 13} catch(QueryException qe) { 14 System.debug('The following exception has occurred: ' + qe.getMessage()); 15} - SObjectException
- insert の間のみ変更可能な update ステートメント内の項目の変更など、sObject レコードに関する問題を示す例外。
- この例では、try ブロックで SObjectException が発生し、catch ブロックでキャッチされます。請求書明細を照会し、その Name 項目のみを選択します。次に、照会された sObject の Description__c 項目を取得しようとしますが、この項目は SELECT ステートメントで照会された項目リストに含まれていないため取得できません。その結果、SObjectException が発生します。この例外は catch ブロックでキャッチされ、デバッグログには「The following exception has occurred: SObject row was retrieved via SOQL without querying the requested field: Invoice_Statement__c.Description__c」と表示されます。
1try { 2 Invoice_Statement__c inv = new Invoice_Statement__c( 3 Description__c='New Invoice'); 4 insert inv; 5 6 // Query the invoice we just inserted 7 Invoice_Statement__c v = [SELECT Name FROM Invoice_Statement__c WHERE Id = :inv.Id]; 8 // Causes an SObjectException because we didn't retrieve 9 // the Description__c field. 10 String s = v.Description__c; 11} catch(SObjectException se) { 12 System.debug('The following exception has occurred: ' + se.getMessage()); 13}
共通例外メソッド
- getCause: 例外オブジェクトとして例外の原因を返します。
- getLineNumber: 例外が発生した箇所の行番号を返します。
- getMessage: ユーザに表示されるエラーメッセージを返します。
- getStackTraceString: 発生した例外のスタック追跡を文字列として返します。
- getTypeName: DMLException、ListException、MathException などの例外種別を返します。
例
次の例を実行して、これらの共通メソッドが何を返すか確認しましょう。
1try {
2 Merchandise__c m = [SELECT Name FROM Merchandise__c LIMIT 1];
3 // Causes an SObjectException because we didn't retrieve
4 // the Total_Inventory__c field.
5 Double inventory = m.Total_Inventory__c;
6} catch(Exception e) {
7 System.debug('Exception type caught: ' + e.getTypeName());
8 System.debug('Message: ' + e.getMessage());
9 System.debug('Cause: ' + e.getCause()); // returns null
10 System.debug('Line number: ' + e.getLineNumber());
11 System.debug('Stack trace: ' + e.getStackTraceString());
12}すべての System.debug ステートメントの出力は、次のようになります。
17:38:04:149 USER_DEBUG [7]|DEBUG|Exception type caught: System.SObjectException
17:38:04:149 USER_DEBUG [8]|DEBUG|Message: SObject row was retrieved via SOQL without querying the requested field: Merchandise__c.Total_Inventory__c
17:38:04:150 USER_DEBUG [9]|DEBUG|Cause: null
17:38:04:150 USER_DEBUG [10]|DEBUG|Line number: 5
17:38:04:150 USER_DEBUG [11]|DEBUG|Stack trace: AnonymousBlock: line 5, column 1
catch ステートメントの引数種別は、汎用的な Exception 種別です。より具体的な SObjectException をキャッチします。これが行われているかどうか確認するには、デバッグ出力で e.getTypeName() の戻り値を調べます。出力には、エラーメッセージ、例外が発生した行番号、スタック追跡など、SObjectException の他のプロパティも含まれます。getCause はなぜ null を返したのでしょうか。このサンプルでは、この前にこの例外を発生させる例外 (内部例外) がないためです。「カスタム例外の作成」には、getCause の戻り値が実際の例外となる例があります。
その他の例外メソッド
DmlException など、いくつかの例外種別には、その種別にのみ適用され、他の例外とは共通ではない次のような特定の例外メソッドがあります。
- getDmlFieldNames(Index of the failed record): 指定されたエラーレコードのエラーの原因となった項目の名前を返します。
- getDmlId(Index of the failed record): 指定されたエラーレコードのエラーの原因となったエラーレコードの ID を返します。
- getDmlMessage(Index of the failed record): 指定されたエラーレコードに関するエラーメッセージを返します。
- getNumDml: エラーレコードの数を返します。
例
1Merchandise__c m1 = new Merchandise__c(
2 Name='Coffeemaker',
3 Description__c='Kitchenware',
4 Price__c=25,
5 Total_Inventory__c=1000);
6// Missing the Price and Total_Inventory fields
7Merchandise__c m2 = new Merchandise__c(
8 Name='Coffeemaker B',
9 Description__c='Kitchenware');
10// Missing all required fields
11Merchandise__c m3 = new Merchandise__c();
12Merchandise__c[] mList = new List<Merchandise__c>();
13mList.add(m1);
14mList.add(m2);
15mList.add(m3);
16
17try {
18 insert mList;
19} catch (DmlException de) {
20 Integer numErrors = de.getNumDml();
21 System.debug('getNumDml=' + numErrors);
22 for(Integer i=0;i<numErrors;i++) {
23 System.debug('getDmlFieldNames=' + de.getDmlFieldNames(i));
24 System.debug('getDmlMessage=' + de.getDmlMessage(i));
25 }
26}上記のサンプルでは、try ブロックに含まれている初期コードがすべて含まれているわけではありません。例外が発生する可能性があるコード部分のみが try ブロック内にラップされています。この場合、insert ステートメントは入力データが有効でない場合に DML 例外を返す可能性があります。insert 操作で発生した例外は、その後の catch ブロックでキャッチされます。このサンプルを実行した後、次のような System.debug ステートメントの出力が表示されます。
14:01:24:939 USER_DEBUG [20]|DEBUG|getNumDml=2
14:01:24:941 USER_DEBUG [23]|DEBUG|getDmlFieldNames=(Price, Total Inventory)
14:01:24:941 USER_DEBUG [24]|DEBUG|getDmlMessage=Required fields are missing: [Price, Total Inventory]
14:01:24:942 USER_DEBUG [23]|DEBUG|getDmlFieldNames=(Description, Price, Total Inventory)
14:01:24:942 USER_DEBUG [24]|DEBUG|getDmlMessage=Required fields are missing: [Description, Price, Total Inventory]
DML エラーの数は、リストのうち 2 つの品目で挿入が失敗したため、正しく 2 つと報告されています。また、エラーが発生した項目名と、各エラーレコードのエラーメッセージも出力に書き出されます。