はじめに
Apexは、Salesforce上でビジネスロジックを実装できる、Javaに似たプログラミング言語です。
データ型、変数、および関連する言語構成要素についても同様で、今回取り上げるコレクションは
Apex のコレクションはリスト、セット、または対応付けで構成されます。
・リスト
リストは、インデックスで識別される要素の順序付けされたコレクションです。
・セット
セットは、重複を含まない要素の順序付けされていないコレクションです。
・対応付け
対応付けは、単一の値に一意のキーを対応付ける、キー – 値のペアのコレクションです。
Apex 開発者ガイドより
と説明されています。
リストは「List」、セットは「Set」、対応付けは…
一瞬考えてしまいますが、マップのことです。マップは「Map」ですね。
コレクションを初期化する
初期化について、それぞれ2パターンの書き方を紹介します。
どっちの書き方がシンプルか、ちょっとしたことですが、「おっ」と思わせる書き方をするようにしたいですね。
※初期化意外の使い方については、各クラスのAPI仕様を参照して下さい。
Listを初期化する
1 2 3 |
List<String> myList = new List<String>{ 'value1', 'value2', 'value3', 'value1' }; |
1 2 3 4 5 |
List<String> myList = new List<String>(); myList.add('value1'); myList.add('value2'); myList.add('value3'); myList.add('value1'); |
System.debugの結果は以下の通り、Listに追加した通りの順番で値が格納されています。
USER_DEBUG [4]|DEBUG|(value1, value2, value3, value1)
Setを初期化する
1 2 3 |
Set<String> mySet = new Set<String>{ 'value1', 'Value2', 'value3', 'value1' }; |
1 2 3 4 5 |
Set<String> mySet = new Set<String>(); mySet.add('value1'); mySet.add('value2'); mySet.add('value3'); mySet.add('value1'); |
System.debugの結果は以下の通り、Setに追加した順番は維持されず、また、重複した値「value1」は、1つだけ格納されています。
USER_DEBUG [4]|DEBUG|{Value2, value1, value3}
Mapを初期化する
1 2 3 |
Map<String, String> myMap = new Map<String, String>{ 'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3', 'key4' => 'value1' }; |
1 2 3 4 5 |
Map<String, String> myMap = new Map<String, String>(); myMap.put('key1', 'value1'); myMap.put('key2', 'value2'); myMap.put('key3', 'value3'); myMap.put('key4', 'value1'); |
System.debugの結果は以下の通り、Mapに追加した通りの順番で値が格納されています。
USER_DEBUG [4]|DEBUG|{key1=value1, key2=value2, key3=value3, key4=value1}
一意のキーに対応するキーと値のペアを持つので、重複したキーを指定すると、
1 2 3 |
Map<String, String> myMap = new Map<String, String>{ 'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3', 'key1' => 'value4' }; |
後から指定した値で上書きされます。
USER_DEBUG [4]|DEBUG|{key1=value4, key2=value2, key3=value3}
コレクションでSOQLの結果を受け取る
ListでSOQLの結果を受け取る
通常と言うと語弊があるかもしれませんが、通常ListでSOQLの結果を受け取ります。
素直でイメージし易い書き方ですね。
1 |
List<Account> accountList = new List<Account>([SELECT Id, Name FROM Account]); |
SOQLの結果が0件になる条件を指定していることもあると思います。
(SQOLの結果が1件になる条件を指定したつもりで、実際の結果が0件だった。とか。)
以下は、SOQLの結果が0件(Listが空)という状態で、インデックス0にアクセスした場合をイメージしたサンプルなので、範囲外のインデックスへのアクセス例外(System.ListException)が発生します。
1 2 |
List<Account> accountList = new List<Account>([SELECT Id, Name FROM Account WHERE Name='foo']); System.debug(accountList.get(0)); |
実装している時やテストしている時は気付けなかった、ということがありがちですから、Listを使用するときは空チェックをするようにしましょう。
1 2 3 4 |
List<Account> accountList = new List<Account>([SELECT Id, Name FROM Account WHERE Name='foo']); if (!accountList.isEmpty()) { System.debug(accountList.get(0)); } |
SetでSOQLの結果を受け取る
ListとSetとMap、粒度を合わせたくて例を挙げてますが、書いてる本人は使ったことありません。
※SOQLの結果を受け取る時に使ったことはありません。です。
Setそのものは、重複を含まないという特徴を有効に使わせてもらってます。
1 |
Set<Account> accountSet = new Set<Account>([Select Id, Name FROM Account]); |
MapでSOQLの結果を受け取る
keyがId、valueがsObjectのMapでSQQLの結果を受け取ります。
Listの場合は、ループの中でIdを比較して対象のsObjectを取り出しますが、
Mapの場合は、Idを指定して対象のsObjectを取り出すことができますから、ループしなくて済みますね。
1 |
Map<Id, Account> accountMap = new Map<Id, Account>([SELECT Id, Name FROM Account]); |
ListとMap変換のTips
ListからMapを生成
1 2 |
List<Account> accountList = new List<Account>([SELECT Id, Name FROM Account]); Map<Id, Account> accountMap = new Map<Id, Account>(accountList); |
※気付かれてると思いますが、やってることは「MapでSOQLの結果を受け取る」です。
Mapの値でListを生成
1 2 |
Map<Id, Account> accountMap = new Map<Id, Account>([SELECT Id, Name FROM Account]); List<Account> accountList = new List<Account>(accountMap.values()); |
MapのキーでListを生成
12
Map<Id, Account> accountMap = new Map<Id, Account>([SELECT Id, Name FROM Account]);List<Id> idList = new List<Id>(accountMap.keySet());
おわりに
1 2 |
Map<Id, Account> accountMap = new Map<Id, Account>([SELECT Id, Name FROM Account]); List<Id> idList = new List<Id>(accountMap.keySet()); |
おわりに
内容としては、既に多くの方がまとめられてますし、Salesforceが公開しているApex 開発者ガイドを見ればいいというものだったりする訳ですが、今回あらためて自分の言葉でまとめてみました。
自社のSalesforceエンジニアはもちろん、これを見たSalesforceエンジニアの一助になればいいかな、と思ってます。