SalesforceでforEachループを行う方法|実例付き

※本サイトにはプロモーション・広告が含まれています。

(最終更新月: 2024年2月)

✔以下の疑問をお持ちの方へ向けた記事です

「Salesforce ApexにおけるforEachループとは何か?」
「forEachループを使用するメリットとは?」
「ApexでのforEachループの使用例は?」

✔当記事を読むことで得られる知識

  • Salesforce ApexでのforEachループの基本概念
  • forEachループの使用方法と効率的なコーディングのためのヒント
  • ApexでのforEachループを使用した具体的なコーディング例

forEachループは、コレクション(リスト、セット、マップなど)内の各要素に対して繰り返し処理をおこなう際に使用され、コードの可読性と効率を向上させられます。

Salesforceの開発者にとって、コレクションデータの処理をより簡潔に、効率的におこなうための重要な情報源です。

ぜひ最後までご覧ください。

Salesforce

定義や属性などは公式ガイドを必ず参考にしましょう。

当記事では、主にその使い方を具体例とともに解説します。

筆者プロフィール

筆者プロフィールアイコン

【現職】プロダクトマネージャー

プロダクトマネージャーとして、Apex・Visualforceの開発エンジニアとして、以下のようなプロジェクトに従事してきました

  • 新規事業の立ち上げに伴うビジネスプロセス構築とSalesforceのカスタマイズ
  • SFDXを活用した大規模リリース
  • Visualforce等による一般ユーザー向けサイト・アプリケーションの構築

相談・業務の依頼も承ります。ご質問・ご希望をお問い合わせください。

ApexにおけるForEachループの基本

こちらでは、プログラミング言語ApexにおけるForEachループについて解説します。

forEachループは、コードの可読性を高めつつ、繰り返し処理を効率的に実行するために欠かせない構文です。

  • ForEachループとは何か
  • ForEachループの利点
  • Apexにおける他のループ構文との比較

ForEachループとは何か

ForEachループは、コレクションまたは配列に含まれる各要素に対して、指定した処理を繰り返しておこなうための命令のこと。

具体的には、for (型 変数名 : コレクション名) の形式をとります。

例えば、Integer型のリストList<Integer> numbersに含まれるすべての数値を画面に表示する場合は、以下のように書きます。

List<Integer> numbers = new List<Integer>{1, 2, 3};
for (Integer num : numbers) {
    System.debug(num);
}

このコードは、numbersリストの各要素に対してデバッグログの出力をおこないます。

ForEachループの利点

ForEachループは主に、そのシンプルさと直感性によってほかのループ構文と区別されます。

とくに、大きな利点は次のとおりです。

  • コードの可読性が高まり、何をしているかが一目でわかります。
  • カウンタ変数やIteratorを使用する必要がなく、エラーを引き起こしにくいです。
  • コレクションの全要素を簡単に扱え、コーディングの手間が省けます。

たとえば、アカウントリストの名前をすべて出力したい場合、ForEachループを使って以下のように簡単に書けます。

List<Account> accounts = [SELECT Name FROM Account];
for (Account a : accounts) {
    System.debug(a.Name);
}

Apexにおける他のループ構文との比較

Apexには、whileループやfor(初期化; 条件; 更新)のような他のループ構文も存在します。

これらは特定の条件の下で繰り返し処理に利用されますが、ForEachループはコレクションの各要素に対したシンプルな繰り返し処理に適しているものです。

条件に応じてループを繰り返す必要がある場合はforまたはwhileを使用し、コレクションのすべての要素に同じ操作を行いたい場合はForEachループが最適です。

forループの例

for (Integer i=0; i<100; i++;){
   //処理をおこなう
}

ForEachループの使用方法

こちらでは、実際にForEachループをどのように使うか、基本的な構文からリスト、セット、マップでの使用方法まで、具体的なコード例を交えて詳しく説明していきます。

  • 基本的なForEachループの構文
  • リストとセットでのForEachループの使用
  • マップでのForEachループの使用

基本的なForEachループの構文

ForEachループの基本的な構文は非常にシンプルです。以下の例では、String型のリストに対してForEachループを適用し、各文字列の長さを出力しています。

List<String> strings = new List<String>{'Hello', 'World', 'Apex'};
for (String s : strings) {
    System.debug(s.length());
}

上記のコードでは、リストstrings内の各文字列'Hello''World''Apex'の長さがデバッグログとして表示されます。

リストとセットでのForEachループの使用

ForEachループはリストだけでなくセットにも使用可能です。ここでは、Integer型のセットにForEachループを適用する例を示します。

Set<Integer> uniqueNumbers = new Set<Integer>{1, 2, 3, 2, 1};
for (Integer num : uniqueNumbers) {
    System.debug(num);
}

このコードでは、uniqueNumbersセット内の重複がない数字が出力されます。セットの場合、重複する要素は一度しかループ内で処理されません。

マップでのForEachループの使用

ForEachループをマップに適用するときは、マップのキーまたは値、あるいは両方にアクセスできます。以下に例を示します。

Map<Integer, String> m = new Map<Integer, String>{1 => 'One', 2 => 'Two', 3 => 'Three'};
for (Integer key : m.keySet()) {
    System.debug('Key: ' + key + ', Value: ' + m.get(key));
}

このコードでは、mapのすべてのキーとそれに対応する値がデバッグログとして出力されます。

ForEachループの実践的活用例

ForEachループは多岐にわたる状況で役立ちます。

こちらでは、コレクションの反復処理、条件に基づくフィルタリング、集約処理とデータ変換の例を展開していきましょう。

  • コレクションの要素の反復処理
  • 条件に基づくデータのフィルタリング
  • 集約処理とデータ変換

コレクションの要素の反復処理

コレクションのすべての要素に対してある処理をする場合、ForEachループは非常に効果的です。

例えば、Contactオブジェクトのリストの全100個の連絡先に対して同じメールを送信するコードは次のようになります。

List<Contact> contacts = [SELECT Email FROM Contact WHERE Email != null LIMIT 100];
for (Contact c : contacts) {
    // SendEmailメソッドを仮定
    SendEmail(c.Email, 'こんにちは!', '今月のお知らせです。');
}

このコードは、メールアドレスを持つ連絡先に対してメール送信の処理を行います。

条件に基づくデータのフィルタリング

特定の条件を満たす要素だけを処理したい場合は、ForEachループ内で条件文を用います。

以下の例では、特定の条件を満たすアカウントだけに処理を適用。

List<Account> accounts = [SELECT Id, Name, AnnualRevenue FROM Account];
for (Account a : accounts) {
    if (a.AnnualRevenue > 1000000) {
        System.debug(a.Name + 'は高収益です。');
    }
}

このコードは、年間収益が100万以上のアカウントに対して、デバッグログに特定のメッセージを出力します。

集約処理とデータ変換

データの集約や変換にもForEachループが使用されます。

たとえば、複数のオブジェクトの情報を統合した集約データを作成する場合、次のようにします。

List<Opportunity> opportunities = [SELECT Amount FROM Opportunity];
Double totalAmount = 0;
for (Opportunity opp : opportunities) {
    totalAmount += opp.Amount;
}
System.debug('全商談の合計金額: ' + totalAmount);

このコードは、すべての商談の合計金額を計算して、デバッグログに出力します。

ForEachループのベストプラクティス

コードのパフォーマンスや制限に関する考慮、エラーハンドリングといった点でベストプラクティスを理解することが重要です。

ForEachループを最適に利用するためのポイントを以下に説明します。

  • パフォーマンスへの影響の理解
  • ガバナ制限との関係
  • エラーハンドリングと例外処理

パフォーマンスへの影響の理解

ForEachループは便利ですが、大きなデータセットに対して使用する際はパフォーマンスへの影響を考慮する必要があります。

なぜなら、コレクション内の要素が非常に多い場合、時間がかかったりメモリリソースを多く使用したりする可能性があるからです。

]パフォーマンスの最適化を試みる際には、バッチ処理を利用したり、ループの前にデータを適切にフィルタリングしたりすることが役立ちます。

ガバナ制限との関係

Salesforceにはガバナ制限があり、一定のリソース制限内でコードを実行する必要があります。

ForEachループを使用するときは、SOQLクエリの呼び出し回数やDML操作の制限を意識するべきです。

たとえば、以下のようにループ内で無制限にDML操作をおこなうのは避けましょう。

// 非推奨の例
for (Account a : [SELECT Id FROM Account]) {
    // ガバナ制限を超えてしまう可能性がある
    update a; 
}

代わりにラージデータボリューム(LDV)を考慮し、バルク化を検討することが肝要です。

エラーハンドリングと例外処理

ForEachループ内で処理を実行しているとき、予期しないエラーが発生することがあります。

コードを強靭にするためには、適切なエラーハンドリングが必要です。

例外処理により、エラーが発生した場合でもアプリケーションが中断せずに処理を続けられます。

「try-catch」ブロックを適用して例外をキャッチし、ロギングを行うことが有効です。

for (Object obj : someList) {
    try {
        // 何らかの処理...
    } catch (Exception e) {
        // エラーロギング...
    }
}

このように例外処理を実装することで、ForEachループでの安全な実行を保証します。

よくある間違いとトラブルシューティング

ForEachループの使用中に発生する可能性のある一般的な問題と、それを回避するためのトラブルシューティングの方法について解説します。

  • 無限ループの回避
  • コレクションの同時変更の問題
  • メモリ使用量の最適化

無限ループの回避

ForEachループでは通常、無限ループの問題は少ないですが、ループ内でコレクションを誤って変更した場合に起こりうります。

例えば、ループ内でコレクションに要素を追加するような操作は、ループの終了条件を永遠に成立させないため避けるべきです。

List<Integer> numbers = new List<Integer>{1, 2, 3};
for (Integer num : numbers) {
    if (num < 5) {
        numbers.add(num + 1); // 非推奨:コレクションを変更している
    }
}

上記のコードは無限ループに陥る可能性があるので、回避するためには別のリストを作成するか、ループを切り上げる条件を明確にする必要があります。

コレクションの同時変更の問題

ForEachループ中にコレクションを変更すると、「ConcurrentModificationException」の原因になります。

とくに、削除や順序の変更などをおこなう場合、エラーを引き起こすリスクがあります。

解決策としては、元のコレクションを直接変更せず、変更が必要な要素を一時的なコレクションに保存し、ループの後で変更を適用する方法があります。

List<Integer> numbers = new List<Integer>{1, 2, 3, 4, 5};
List<Integer> toRemove = new List<Integer>();

for (Integer num : numbers) {
    if (num % 2 == 0) {
        toRemove.add(num);
    }
}

for (Integer num : toRemove) {
    numbers.remove(num);
}

この方法では、ループ中に削除すべき要素を別のリストtoRemoveに一時的に格納し、後で安全に削除しています。

メモリ使用量の最適化

メモリ使用量を最適化するためには、とくに大きなコレクションを扱う際に、不要なオブジェクトの生成を避けることが重要。

例えば、不変のリテラルをループの中で繰り返し生成するのではなく、変数に一度代入して再利用するなどの最適化が可能です。

final String greeting = 'こんにちは!'; // 不変のリテラルを変数に代入
for (Contact c: contacts) {
    // greeting変数を再利用
    System.debug(greeting + ' ' + c.Name);
}

ループの各イテレーションで新たな文字列オブジェクトの生成を避け、メモリ消費を抑制できます。

まとめ

当記事では、ApexプログラミングにおけるForEachループの基本から実践的な使用法、さらにはトラブルシューティングに至るまで幅広く解説しました。

ForEachループはコードの可読性を向上させる優れたツールですが、その利用には適切な慎重さと理解が必要です。

ガバナ制限、パフォーマンス、エラーハンドリングといった留意点を押さえながら、Apex開発を進めていくことで、より効率的かつ堅牢なアプリケーションを作成できるでしょう。

以上を参考にしながら、Apexの繰り返し処理を上手に活用してください。

タイトルとURLをコピーしました