Apex Collections: List, Set, and Map
Apex Collections in Salesforce are powerful data structures used to store and manipulate groups of data. There are three primary types: List, Set, and Map. **List:** A List is an ordered collection of elements that allows duplicates. Elements are indexed starting from 0. Lists are commonly used wh… Apex Collections in Salesforce are powerful data structures used to store and manipulate groups of data. There are three primary types: List, Set, and Map. **List:** A List is an ordered collection of elements that allows duplicates. Elements are indexed starting from 0. Lists are commonly used when you need to maintain insertion order or access elements by their position. Example: ``` List<String> names = new List<String>(); names.add('Alice'); names.add('Bob'); names.add('Alice'); // Duplicates allowed String first = names[0]; // 'Alice' ``` Lists are heavily used in DML operations, SOQL query results, and batch processing. **Set:** A Set is an unordered collection of unique elements — duplicates are automatically excluded. Sets are ideal for ensuring data uniqueness and performing efficient lookups. Example: ``` Set<Id> accountIds = new Set<Id>(); accountIds.add('001XXXXXXXXXXXX'); accountIds.add('001XXXXXXXXXXXX'); // Ignored, duplicate ``` Sets are frequently used to collect record IDs for filtering SOQL queries with the IN clause, improving bulkification in triggers. **Map:** A Map is a collection of key-value pairs where each key is unique. Maps provide fast lookups by key and are essential for correlating related data. Example: ``` Map<Id, Account> accountMap = new Map<Id, Account>([SELECT Id, Name FROM Account]); Account acc = accountMap.get('001XXXXXXXXXXXX'); ``` Maps are critical in trigger patterns for accessing related records without additional SOQL queries, helping avoid governor limits. **Key Considerations for the PD1 Exam:** - All collections can be nested (e.g., Map<Id, List<Contact>>). - Collections support iteration via for loops. - Lists are returned by SOQL queries by default. - Maps can be directly constructed from SOQL results using `new Map<Id, SObject>(query)`. - Understanding bulkification patterns using Sets and Maps in triggers is essential. - Collections help developers stay within Salesforce governor limits by reducing redundant queries and DML operations. Mastering these collections is fundamental for writing efficient, scalable Apex code.
Apex Collections: List, Set, and Map – Complete Guide for Salesforce Platform Developer 1 Exam
Why Are Apex Collections Important?
Apex Collections are one of the most fundamental and frequently tested topics on the Salesforce Platform Developer 1 (PD1) exam. They form the backbone of data manipulation in Apex code. Almost every real-world Salesforce development scenario — from trigger handlers to batch classes — relies on collections to efficiently store, organize, retrieve, and process data. Understanding collections is essential not only for passing the exam but also for writing bulkified, governor-limit-friendly code that follows Salesforce best practices.
On the exam, you can expect multiple questions that test your understanding of the three primary collection types, their characteristics, when to use each, and how they behave in various scenarios.
What Are Apex Collections?
Collections in Apex are data structures that allow you to store and manage groups of elements. There are three types of collections in Apex:
1. List
2. Set
3. Map
Each serves a distinct purpose and has unique characteristics. Let us explore each in detail.
1. List
A List is an ordered collection of elements that allows duplicates. Elements in a List are indexed, starting from index 0.
Key Characteristics:
- Ordered: Elements maintain the order in which they are added.
- Allows duplicates: The same value can appear multiple times.
- Index-based access: You can access elements by their index position (e.g., myList[0]).
- Dynamic sizing: Lists grow automatically as elements are added.
- Can contain any data type: Primitives (String, Integer, etc.), sObjects, custom objects, or even other collections.
Declaration and Initialization:
List<String> names = new List<String>();
List<Account> accounts = new List<Account>();
List<Integer> numbers = new List<Integer>{1, 2, 3, 4, 5};
Common Methods:
- add(element) – Adds an element to the end of the list.
- add(index, element) – Inserts an element at the specified index.
- get(index) – Returns the element at the specified index.
- set(index, element) – Replaces the element at the specified index.
- size() – Returns the number of elements in the list.
- remove(index) – Removes the element at the specified index.
- clear() – Removes all elements from the list.
- contains(element) – Returns true if the list contains the specified element.
- isEmpty() – Returns true if the list has no elements.
- sort() – Sorts the elements in ascending order.
Important Notes:
- SOQL queries return results as List<sObject>. For example: List<Account> accts = [SELECT Id, Name FROM Account];
- You can use array notation with lists: String firstName = names[0];
- Attempting to access an index that does not exist throws a ListException (System.ListException: List index out of bounds).
2. Set
A Set is an unordered collection of unique elements. It automatically prevents duplicate values.
Key Characteristics:
- Unordered: There is no guaranteed order of elements.
- No duplicates: Each element must be unique. Adding a duplicate is silently ignored.
- No index-based access: You cannot access elements by position.
- Useful for ensuring uniqueness: Commonly used to collect unique IDs, filter duplicates, or check membership.
Declaration and Initialization:
Set<String> emailSet = new Set<String>();
Set<Id> accountIds = new Set<Id>();
Set<Integer> uniqueNumbers = new Set<Integer>{1, 2, 3};
Common Methods:
- add(element) – Adds an element to the set. Returns true if added, false if it already exists.
- contains(element) – Returns true if the set contains the specified element.
- remove(element) – Removes the specified element from the set.
- size() – Returns the number of elements.
- isEmpty() – Returns true if the set has no elements.
- clear() – Removes all elements.
- addAll(collection) – Adds all elements from another collection.
- containsAll(collection) – Returns true if the set contains all elements from the specified collection.
- retainAll(collection) – Retains only the elements contained in the specified collection.
- removeAll(collection) – Removes all elements that are also contained in the specified collection.
Important Notes:
- Sets are commonly used in conjunction with SOQL queries to collect record IDs. For example, you often build a Set<Id> from trigger records and then use it in a WHERE clause: WHERE Id IN :accountIds.
- Sets are highly efficient for lookups (contains() is O(1) on average).
- You can initialize a Set from a List to remove duplicates: Set<String> uniqueNames = new Set<String>(namesList);
3. Map
A Map is a collection of key-value pairs where each key is unique and maps to exactly one value.
Key Characteristics:
- Key-value structure: Each entry consists of a unique key and its associated value.
- Keys must be unique: If you add a key that already exists, the previous value is overwritten.
- Values can be duplicated: Multiple keys can map to the same value.
- Unordered: There is no guaranteed order of entries.
- Extremely useful for lookups: Allows quick retrieval of a value by its key.
Declaration and Initialization:
Map<Id, Account> accountMap = new Map<Id, Account>();
Map<String, Integer> scoreMap = new Map<String, Integer>();
Map<Id, Account> accountMap = new Map<Id, Account>([SELECT Id, Name FROM Account]);
Common Methods:
- put(key, value) – Adds or updates a key-value pair.
- get(key) – Returns the value associated with the specified key. Returns null if the key does not exist.
- containsKey(key) – Returns true if the map contains the specified key.
- keySet() – Returns a Set of all keys in the map.
- values() – Returns a List of all values in the map.
- remove(key) – Removes the entry with the specified key.
- size() – Returns the number of key-value pairs.
- isEmpty() – Returns true if the map has no entries.
- clear() – Removes all entries.
Important Notes:
- A very powerful pattern is initializing a Map directly from a SOQL query: Map<Id, Account> acctMap = new Map<Id, Account>([SELECT Id, Name FROM Account]); This automatically uses the record Id as the key and the sObject as the value.
- Maps are heavily used in trigger patterns to avoid nested loops and SOQL queries inside loops.
- Using get() on a key that does not exist returns null, it does NOT throw an exception.
- keySet() returns a Set, and values() returns a List (because values can be duplicated).
How Do Collections Work Together?
In real-world Salesforce development and on the exam, you will frequently see all three collection types used together in a single pattern. Here is a common scenario:
Step 1: Use a Set to collect unique IDs from trigger records.
Step 2: Use the Set in a SOQL query to fetch related records.
Step 3: Store the query results in a Map for efficient lookup.
Step 4: Use a List to accumulate records that need to be updated or inserted.
Example:
Set<Id> accountIds = new Set<Id>();
for (Contact con : Trigger.new) {
accountIds.add(con.AccountId);
}
Map<Id, Account> accountMap = new Map<Id, Account>(
[SELECT Id, Name, Industry FROM Account WHERE Id IN :accountIds]
);
List<Account> accountsToUpdate = new List<Account>();
for (Contact con : Trigger.new) {
Account acct = accountMap.get(con.AccountId);
if (acct != null) {
acct.Description = 'Updated';
accountsToUpdate.add(acct);
}
}
update accountsToUpdate;
This pattern is critical for the exam and for real development.
Comparison Summary Table
Feature | List | Set | Map
Ordered? | Yes | No | No
Allows Duplicates? | Yes | No | Keys: No, Values: Yes
Index-based Access? | Yes | No | No (key-based access)
Use Case | Ordered data, DML operations | Unique values, filtering | Key-value lookups
SOQL Results? | Yes (default) | No (but can be created from List) | Yes (with Id as key)
Exam Tips: Answering Questions on Apex Collections: List, Set, and Map
Tip 1: Know the Core Differences
The exam frequently tests whether you can distinguish between List, Set, and Map. Remember: List = ordered + duplicates allowed, Set = unordered + unique only, Map = key-value pairs with unique keys. If a question asks about maintaining insertion order, the answer involves a List. If uniqueness is required, think Set. If you need to look up a value by a key, think Map.
Tip 2: Watch for Duplicate Behavior
Questions may ask what happens when you add a duplicate element. For a List, the duplicate is added. For a Set, the duplicate is silently ignored (no error is thrown). For a Map, putting a duplicate key overwrites the previous value.
Tip 3: Understand SOQL and Collections
Know that SOQL queries return a List<sObject> by default. Know the pattern of constructing a Map directly from a SOQL query: Map<Id, Account> m = new Map<Id, Account>([SELECT ...]); — this is tested frequently. The Id field is automatically used as the key even if it is not explicitly in the SELECT clause (though best practice is to include it).
Tip 4: Understand Null and Exception Behavior
- Calling get() on a Map with a non-existent key returns null (no exception).
- Accessing a List index out of bounds throws a System.ListException.
- Sets and Maps can contain null as an element/key (but this is generally bad practice).
Tip 5: Know the Return Types of Map Methods
- keySet() returns a Set.
- values() returns a List.
This distinction is tested on the exam. Values return a List because values can have duplicates; keys return a Set because keys are always unique.
Tip 6: Bulkification Patterns
Many exam questions test whether you understand how to use collections to avoid governor limit violations. Never put SOQL queries or DML statements inside a loop. Instead, use Sets to collect IDs, Maps for lookups, and Lists to accumulate DML operations. If you see a code snippet with a query or DML inside a for loop, that is almost always the wrong answer.
Tip 7: Initialization from Other Collections
You can create a Set from a List: Set<String> s = new Set<String>(myList); — this removes duplicates.
You can create a List from a Set: List<String> l = new List<String>(mySet);
You can create a Map from a list of sObjects: Map<Id, Account> m = new Map<Id, Account>(accountList);
Tip 8: Iterating Over Collections
- Lists can be iterated with a for loop using index or the enhanced for-each loop.
- Sets can only be iterated with the for-each loop (no index access).
- Maps can be iterated by looping over keySet() or values().
Tip 9: Read Code Carefully
Exam questions often present code snippets and ask what the output is or whether the code compiles. Pay close attention to:
- The collection type being used
- Whether the code tries to use index access on a Set (this will NOT compile)
- Whether a put() call on a Map overwrites an existing entry
- Whether a List is being used where a Set would be more appropriate (or vice versa)
Tip 10: Nested Collections
Apex supports nested collections such as Map<Id, List<Contact>> which is commonly used for grouping child records by parent Id. Understand that this is valid and is a common pattern in trigger handlers.
Tip 11: Commonly Tested Scenarios
- What is the size of a Set after adding duplicate values? (Answer: only unique values count)
- What does Map.get() return for a key that does not exist? (Answer: null)
- What happens when you access an index beyond the List size? (Answer: ListException)
- How do you get all keys from a Map? (Answer: keySet())
- Can you use a Set in a SOQL WHERE IN clause? (Answer: Yes)
- What is the result of new Map<Id, Account>([SELECT Id, Name FROM Account])? (Answer: a Map with Account Id as key and Account record as value)
Final Exam Strategy:
When you encounter a collections question on the exam, first identify which collection type is being used or should be used. Then check for duplicate handling, access patterns, and governor limit compliance. Eliminate answers that show SOQL/DML inside loops, incorrect method calls (like using get(index) on a Set), or misunderstanding of duplicate behavior. If a question asks for the best approach, favor the pattern that uses Set for IDs, Map for lookups, and List for DML — this is the gold standard Salesforce development pattern.
🎓 Unlock Premium Access
Salesforce Certified Platform Developer I + ALL Certifications
- 🎓 Access to ALL Certifications: Study for any certification on our platform with one subscription
- 2750 Superior-grade Salesforce Certified Platform Developer I practice questions
- Unlimited practice tests across all certifications
- Detailed explanations for every question
- PD1: 5 full exams plus all other certification exams
- 100% Satisfaction Guaranteed: Full refund if unsatisfied
- Risk-Free: 7-day free trial with all premium features!