Apex Map Methods in Salesforce: A Complete Guide

Blog / Salesforce · December 11, 2017 · Updated June 10, 2026 · 7 min read
Apex Map Methods in Salesforce: A Complete Guide

In Apex, a Map<K, V> is a collection of unique key → value pairs that lets you look up a value by its key in roughly constant time. Maps are the backbone of efficient, bulk-safe Salesforce code: they let you correlate records, cache query results, and keep SOQL and DML statements out of loops. This guide covers every core Map method, the powerful Map<Id, SObject> SOQL constructor, and the trigger patterns that keep you inside Salesforce governor limits.

Key takeaways

  • A Map<K, V> stores unique keys, each mapped to a single value; values may repeat, keys may not.
  • get() returns null when a key is absent — it never throws an exception.
  • The new Map<Id, Account>([SELECT ...]) constructor auto-keys records by their Id in a single line.
  • Trigger.newMap and Trigger.oldMap are pre-built Map<Id, SObject> maps — the canonical way to compare old vs new field values.
  • Building a Map keyed by a field is the standard bulkification pattern to pull SOQL and DML out of loops.
  • Maps are unordered, and String keys are case-sensitive.

What is a Map in Apex?

A Map is one of the three Apex collection types, alongside List and Set. Each entry pairs a unique key with a value, and both the key and the value can be almost any data type — primitives, sObjects, user-defined classes, or even other collections.

You declare a Map with the Map<KeyType, ValueType> syntax and instantiate it with new. You can start empty, seed it from a map literal, or clone an existing map.

// Empty map: Id keys -> Account values
Map<Id, Account> accountsById = new Map<Id, Account>();

// String -> String, seeded with a map literal
Map<String, String> colorToItem = new Map<String, String>{
    'red'   => 'shirt',
    'blue'  => 'tshirt',
    'black' => 'cap'
};

// Shallow copy of an existing map
Map<String, String> copy = colorToItem.clone();

How do you add, retrieve, and check values?

Use put(key, value) to add or overwrite an entry, get(key) to read a value, and containsKey(key) to test for a key before reading. Because re-put-ting an existing key overwrites the old value, keys always stay unique.

Map<String, Integer> stock = new Map<String, Integer>();
stock.put('apples', 12);
stock.put('pears', 7);
stock.put('apples', 20);          // overwrites 12 -> 20 (keys are unique)

Integer apples  = stock.get('apples');   // 20
Integer mangoes = stock.get('mangoes');  // null (key absent, no error)

Boolean hasPears = stock.containsKey('pears'); // true
Integer count    = stock.size();               // 2

Apex Map methods reference

The table below lists the most-used Map<K, V> instance methods.

Method Signature Returns Description
put put(key, value) V Adds the key/value pair; returns the previous value for that key (or null).
get get(key) V Returns the value mapped to key, or null if the key isn't present.
containsKey containsKey(key) Boolean true if the map contains an entry for key.
keySet keySet() Set<K> Returns a Set of all keys in the map.
values values() List<V> Returns a List of all values in the map.
remove remove(key) V Removes the entry for key and returns its value (or null).
size size() Integer Number of key/value pairs in the map.
isEmpty isEmpty() Boolean true when the map has zero entries.
clear clear() void Removes all entries from the map.
putAll putAll(fromMap) void Copies all entries from another map (or an sObject list) into this map.
clone clone() Map<K,V> Returns a shallow copy of the map.

keySet() returns a Set<K> — so you can iterate the keys or feed them straight into a SOQL IN bind — while values() returns a List<V> you can loop over or pass to DML.

What does the Map<Id, SObject> SOQL constructor do?

One of the most useful Apex idioms is to pass a SOQL query straight into a Map<Id, SObject> constructor. Salesforce automatically uses each record's Id as the key, giving you instant Id-based lookups with no manual loop. Learn the query syntax in our guide on how to run a SOQL query in Salesforce.

// Auto-keyed by Account Id -- no loop needed
Map<Id, Account> accountsById = new Map<Id, Account>(
    [SELECT Id, Name, Industry FROM Account WHERE Industry = 'Technology']
);

// Instant lookup by Id
Account a = accountsById.get(someAccountId);

// keySet() hands you all the Ids as a Set<Id>
Set<Id> accountIds = accountsById.keySet();

How do you use Maps in Apex triggers?

Inside a trigger, Salesforce hands you two ready-made maps: Trigger.newMap and Trigger.oldMap, both typed as Map<Id, SObject>. They let you look up a record by Id and compare its old and new field values — the standard way to detect what changed. (Trigger.oldMap is null on insert, and Trigger.newMap is null on delete.)

trigger AccountTrigger on Account (before update) {
    // Compare new vs old values to detect what changed
    for (Account updated : Trigger.new) {
        Account previous = Trigger.oldMap.get(updated.Id);
        if (updated.Industry != previous.Industry) {
            updated.Description = 'Industry changed from '
                + previous.Industry + ' to ' + updated.Industry;
        }
    }
}

How do Maps help with bulkification and governor limits?

Salesforce enforces governor limits — hard caps such as 100 SOQL queries and 150 DML statements per transaction. The fastest way to blow past them is to run a query or DML inside a loop. Maps solve this: query once, load the results into a Map keyed by a correlating field, then look up related records in memory while you loop.

Below, instead of querying Contacts per Account, we collect the Account Ids first, run a single query, group the Contacts into a Map<Id, List<Contact>>, and correlate everything in one pass.

// 1. Collect parent Ids from the trigger set
Set<Id> accountIds = Trigger.newMap.keySet();

// 2. ONE SOQL query for all related children
Map<Id, List<Contact>> contactsByAccount = new Map<Id, List<Contact>>();
for (Contact c : [SELECT Id, AccountId FROM Contact WHERE AccountId IN :accountIds]) {
    if (!contactsByAccount.containsKey(c.AccountId)) {
        contactsByAccount.put(c.AccountId, new List<Contact>());
    }
    contactsByAccount.get(c.AccountId).add(c);
}

// 3. Correlate parent + children in memory -- no SOQL inside the loop
for (Account acc : Trigger.new) {
    List<Contact> children = contactsByAccount.get(acc.Id);
    Integer childCount = (children == null) ? 0 : children.size();
    System.debug(acc.Name + ' has ' + childCount + ' contacts');
}

Map vs List vs Set: which collection should you use?

Apex gives you three collection types. Pick the one that matches how you need to access the data.

Feature List Set Map
Structure Ordered, indexed sequence Unordered group Key → value pairs
Duplicates Allowed Not allowed Keys unique; values may repeat
Ordering Index order preserved Unordered Unordered
Access by Index (myList[0]) Membership test (contains) Key (myMap.get(key))
Typical use Ordered data, DML, query results Unique values, IN filters Lookups, correlation, caching

Reach for a List when order or indexing matters (see Apex List methods), a Set when you need uniqueness or fast membership checks (see Apex Set methods), and a Map when you need to look something up by a key.

Common Map gotchas to remember

  • Maps are unordered. Never rely on keySet() or values() returning entries in insertion order.
  • String keys are case-sensitive. 'Red' and 'red' are two distinct keys — even though Apex's == operator compares strings case-insensitively, Map keys do not. This trips up many developers.
  • get() returns null for a missing key, so null-check before dereferencing nested collections.
  • keySet() returns the map's key Set — copy it if you need to modify the map while iterating.

Maps, Lists, and Sets together form the foundation of clean, bulk-safe Apex. Need a hand architecting triggers, batch jobs, or a full build? Our Salesforce development team has delivered 50+ projects since 2014.

Frequently Asked Questions

What is a Map in Salesforce Apex?

A Map is an Apex collection of unique key/value pairs. Each key maps to exactly one value, keys must be unique, and both keys and values can be any data type — primitives, sObjects, or custom classes. You use it to quickly look up a value by its key.

How do I get all keys or all values from an Apex Map?

Call keySet() to get a Set of every key, and values() to get a List of every value. keySet() is handy for binding into a SOQL IN clause, while values() gives you a list you can iterate or pass straight to DML.

What happens when you call get() on a key that does not exist?

get() returns null rather than throwing an exception. Use containsKey() first when you need to distinguish a missing key from a key that genuinely maps to a null value.

Are Apex Map keys case-sensitive?

Yes. For String keys, 'Account' and 'account' are treated as two separate keys, even though the Apex == operator compares strings case-insensitively. Normalize the case, for example with toLowerCase(), before using strings as keys if you want case-insensitive behavior.

What is the Map<Id, SObject> SOQL constructor used for?

Passing a SOQL query into new Map<Id, SObject>([SELECT ...]) builds a map automatically keyed by each record's Id. It is the quickest way to get Id-based lookups, and it is why Trigger.newMap and Trigger.oldMap exist as ready-made maps in triggers.

How do Maps help avoid Salesforce governor limits?

Maps let you query once and look up records in memory instead of running SOQL or DML inside a loop. By loading records into a Map keyed by a correlating field, you bulkify your code and stay well under the per-transaction SOQL and DML governor limits.

Share this article