Three core collection types:
List: apex List<Account> accs = new List<Account>(); accs.add(new Account(Name='A')); accs.add(new Account(Name='B')); accs[0]; // indexed access accs.size(); Ordered, allows duplicates, indexed. Good for: SOQL results, processing in sequence, when order matters.
Set: apex Set<Id> ids = new Set<Id>(); ids.add(acc.Id); Boolean has = ids.contains(someId); Unordered, no duplicates, no index. Good for: deduplication, fast contains checks, building IN clauses.
Map: apex Map<Id, Account> accMap = new Map<Id, Account>(); accMap.put(acc.Id, acc); Account a = accMap.get(acc.Id); Set<Id> keys = accMap.keySet(); List<Account> values = accMap.values(); Key-value pairs, fast lookup by key, no duplicate keys. Good for: relating records by Id, in-memory joins, caching.
Conversion patterns:
- List of Ids from List of records:
Set<Id> ids = new Map<Id, Account>(accList).keySet();— clever idiom. - List from Set:
new List<Id>(idSet). - Set from List (dedupe):
new Set<Id>(idList).
Performance:
- List access by index: O(1).
- List `.contains()`: O(n) — slow for large lists.
- Set `.contains()`: O(1).
- Map `.get(key)`: O(1).
Rule: never call list.contains(x) inside a loop that iterates over another list — use a Set for that.
Bulk pattern building blocks:
Set<Id> recordIds = new Set<Id>();— accumulate.Map<Id, ParentRecord__c> parents = new Map<Id, ParentRecord__c>([SELECT ... WHERE Id IN :recordIds]);— fetch as Map.- Loop, call
parents.get(record.Parent__c)— O(1).
