Collections

Apex has three collection types.

Apex has three collection types. They are generic (List<T>, Set<T>, Map<K, V>), can nest, and can hold primitives, sObjects, or user-defined types.

Yes (index from 0) list[i], get(i) Query results, DML batches

No (iteration order is insertion order in practice, but do not rely on it) Unique IDs, membership tests Lookups by ID or key

6.1 List

List<String> colors = new List<String>{ 'red', 'green' };
colors.add('blue');
colors.add(0, 'black');               // insert at index
String first = colors[0];             // 'black'
Integer n = colors.size();            // 4
Boolean has = colors.contains('red'); // true
Integer idx = colors.indexOf('green');
colors.remove(1);                     // remove by index
colors.sort();                        // natural ascending sort
List<String> copy = colors.clone();
colors.addAll(new List<String>{ 'cyan', 'magenta' });
Boolean empty = colors.isEmpty();
colors.clear();

String[] arr = new String[3];         // array syntax is the same as List<String>
List<Account> accs = [SELECT Id, Name FROM Account LIMIT 10];

6.2 Set

Strings in sets and map keys are case-sensitive: 'Acme' and 'acme' are different keys. Normalize with toLowerCase() when needed.

Set<Id> accountIds = new Set<Id>();
for (Contact c : [SELECT AccountId FROM Contact WHERE AccountId != null LIMIT 200]) {
    accountIds.add(c.AccountId);      // duplicates ignored
}

Set<String> a = new Set<String>{ 'x', 'y', 'z' };
Set<String> b = new Set<String>{ 'y', 'z', 'w' };
Set<String> union = a.clone();     union.addAll(b);       // x y z w
Set<String> inter = a.clone();     inter.retainAll(b);    // y z
Set<String> diff  = a.clone();     diff.removeAll(b);     // x
Boolean containsAll = a.containsAll(new Set<String>{ 'x', 'y' });

6.3 Map

Map<String, Integer> stock = new Map<String, Integer>{ 'apple' => 10, 'pear' => 4 };
stock.put('plum', 7);
Integer apples = stock.get('apple');      // 10
Integer none = stock.get('kiwi');         // null (no exception)
Boolean hasPear = stock.containsKey('pear');
Set<String> keys = stock.keySet();
List<Integer> values = stock.values();
stock.remove('pear');

for (String fruit : stock.keySet()) {
    System.debug(fruit + ' → ' + stock.get(fruit));
}

// the most useful idiom in Apex: build a Map<Id, SObject> directly from a query
Map<Id, Account> accountsById = new Map<Id, Account>(
    [SELECT Id, Name FROM Account WHERE Industry = 'Technology']
);
Set<Id> ids = accountsById.keySet();

6.4 Grouping with maps of lists

Map<Id, List<Contact>> contactsByAccount = new Map<Id, List<Contact>>();
for (Contact c : [SELECT Id, AccountId, LastName FROM Contact WHERE AccountId != null]) {
    if (!contactsByAccount.containsKey(c.AccountId)) {
        contactsByAccount.put(c.AccountId, new List<Contact>());
    }
    contactsByAccount.get(c.AccountId).add(c);
}

6.5 Sorting custom types

Since Winter '24 you can also pass a System.Comparator<T> to List.sort() to sort the same type in different ways (§38).

public class Employee implements Comparable {
    public String name;
    public Decimal salary;
    public Employee(String n, Decimal s) { name = n; salary = s; }

    public Integer compareTo(Object other) {
        Employee o = (Employee) other;
        if (salary == o.salary) return 0;
        return salary > o.salary ? -1 : 1;    // descending by salary
    }
}

List<Employee> staff = new List<Employee>{ new Employee('A', 50), new Employee('B', 90) };
staff.sort();