List: an ordered, indexable collection
A List<T> in Apex is an ordered collection that allows duplicate values and is accessed by zero-based index, declared as List<Account> accts = new List<Account>();. Lists are the most common return type for SOQL queries — every SELECT statement without a LIMIT 1 and single-row assignment returns a List<sObject> — and they support methods like add(), remove(), size(), isEmpty(), and sort().
Cricket analogy: A batting order is a List: it's strictly ordered from opener at index 0 down to number 11, and the same player's name could theoretically repeat if used as a placeholder, unlike a Set which forbids duplicates.
Set: unique, unordered membership
A Set<T> in Apex guarantees uniqueness and has no defined order (except Set<sObject>, which is rare and discouraged). Sets are the natural choice for collecting distinct Ids — for example, gathering unique AccountIds from a List<Contact> before a WHERE Id IN :accountIds SOQL query — because adding a duplicate value to a Set silently does nothing rather than throwing an error.
Cricket analogy: The set of countries that have won a Cricket World Cup is a Set: each nation appears exactly once regardless of how many times they've actually won, membership is what matters, not order or count.
// Classic pattern: collect unique parent Ids from a child list, then bulk-query parents
List<Contact> contacts = [SELECT Id, AccountId, Email FROM Contact WHERE Email != null];
Set<Id> accountIds = new Set<Id>();
for (Contact c : contacts) {
if (c.AccountId != null) {
accountIds.add(c.AccountId); // duplicates are silently ignored
}
}
Map<Id, Account> accountsById = new Map<Id, Account>(
[SELECT Id, Name, Industry FROM Account WHERE Id IN :accountIds]
);
List<Contact> contactsToUpdate = new List<Contact>();
for (Contact c : contacts) {
Account relatedAcct = accountsById.get(c.AccountId);
if (relatedAcct != null && relatedAcct.Industry == 'Technology') {
c.Description = 'Tech account contact';
contactsToUpdate.add(c);
}
}
update contactsToUpdate;Map: key-value lookups without repeated queries
A Map<K, V> stores key-value pairs with unique keys, declared as Map<Id, Account> acctsById = new Map<Id, Account>();. The most powerful Apex-specific feature is that any Map<Id, sObject> can be constructed directly from a List<sObject> or SOQL query result, automatically keying every record by its Id — this is the single most common way to turn a query result into an O(1) lookup structure instead of nesting a second query inside a loop.
Cricket analogy: A scorecard app's player-stats lookup keyed by player ID is a Map: given a player ID you get their stats instantly, without scanning every entry in the squad list.
The pattern shown above — query children, collect a Set of parent Ids, query parents into a Map<Id, sObject>, then loop once using map.get(id) — is the canonical way to avoid nested SOQL queries inside a loop, which is illegal from a governor-limit perspective and would throw a runtime error after 100 queries. Maps also support keySet(), values(), containsKey(), and can use composite keys like a concatenated String when a single field isn't unique enough.
Cricket analogy: A stadium's turnstile system doesn't re-verify a ticket's authenticity against the central database on every single re-entry; it caches the validated ticket ID locally, the same way a Map avoids re-querying the same record repeatedly.
Constructing a Map directly from a query, e.g. new Map<Id, Account>([SELECT Id, Name FROM Account]), is idiomatic Apex and automatically deduplicates by Id if the same record somehow appears twice in the result set.
Nesting a SOQL query inside a for loop to look up related records — instead of pre-building a Map<Id, sObject> — is one of the fastest ways to hit 'System.LimitException: Too many SOQL queries: 101' in a bulk operation of more than 100 records.
- List<T> is ordered, indexable by position, and allows duplicate values — the default return type for SOQL queries.
- Set<T> guarantees unique membership with no defined order; ideal for collecting distinct Ids before a bulk query.
- Map<K,V> stores unique keys mapped to values and can be constructed directly from a List<sObject> or query, auto-keyed by Id.
- The canonical bulk pattern: collect a Set of parent Ids, query parents into a Map<Id,sObject>, then use map.get() inside a single loop.
- Adding a duplicate to a Set is a silent no-op; adding a duplicate key to a Map overwrites the previous value.
- Avoid nested SOQL inside loops entirely — Maps built before the loop replace the need for repeated queries.
- Composite String keys let you build Maps keyed by more than one field when a single field isn't unique.
Practice what you learned
1. Which Apex collection type is the idiomatic choice for collecting unique AccountIds from a List<Contact> before running a bulk SOQL query?
2. What happens when you add a value that already exists to a Set<String>?
3. What is a distinctive Apex feature of Map<Id, sObject> construction?
4. Which collection type would you use if you needed to preserve the exact order of records returned by a SOQL query and allow duplicate values?
5. Why does the pattern of building a Map<Id, sObject> before a loop prevent governor limit exceptions?
Was this page helpful?
You May Also Like
Conditionals and Loops in Apex
Learn how Apex controls program flow with if/else branching, switch statements, and for/while loops, including the governor limits that shape how you write them.
sObjects and DML
Understand Apex's sObject data model and the insert, update, upsert, and delete DML operations used to change Salesforce records, including bulk patterns and exception handling.
SOQL Queries
Learn Salesforce Object Query Language (SOQL) syntax for retrieving records, including relationship queries, aggregate functions, and governor-limit-aware query design.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics