put()

Add or replace a mapping, and use the returned previous value to tell a fresh insert from an overwrite in one lookup.

Signature
V put(K key, V value)
  • Added in Java Java 1.2

Parameters

ParameterTypeDescription
$keyKThe key to store the value under.
$valueVThe value to store. Replaces any value already stored for the key.

Return value

VThe previous value associated with the key, or null if there was no mapping (or the key was mapped to null).

Errors

UnsupportedOperationException if the map is unmodifiable; NullPointerException if the key or value is null and the map does not permit nulls; ClassCastException or IllegalArgumentException if the key or value cannot be stored in this map.

put stores a value under a key. A map holds at most one value per key, so putting a key that is already there replaces the old value; it never adds a second entry.

Use the return value

put returns the value it replaced, or null if the key was new. That is the cheapest way to spot duplicates while loading data: one lookup instead of a containsKey followed by a put. If a batch import puts each row by ID and the return value is not null, the batch contained the same ID twice.

The return value is ambiguous on maps that allow null values: null means either "no previous mapping" or "the previous value was null". Avoid storing null values and the ambiguity goes away.

Nulls depend on the implementation

  • HashMap and LinkedHashMap accept one null key and any number of null values.
  • TreeMap with natural ordering throws NullPointerException for a null key, because it has to compare keys.
  • ConcurrentHashMap rejects null keys and null values.
  • Maps from Map.of and Map.copyOf reject every put with UnsupportedOperationException.

Keys must keep their identity

A hash map finds a key through its hashCode and equals. A class that does not override them compares by identity, so a second object with the same fields never matches. If a key object is changed after it was put, its hash code changes and the entry becomes unreachable. Records are good keys: equals and hashCode come from their components. Keep those components immutable.

Order and threads

HashMap does not keep insertion order; LinkedHashMap does and TreeMap sorts by key. A plain HashMap shared between request threads can lose updates or be corrupted when several threads put at once. Use ConcurrentHashMap for shared state in a server, and prefer putIfAbsent, computeIfAbsent or merge over a separate check followed by put, which is a race.

putAll(other) copies every mapping from another map, overwriting keys that already exist.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Indexing rows loaded from a database by primary key and flagging duplicate IDs in an import.
  • Building a set of response headers before writing them to an HTTP exchange.
  • Storing per-tenant cached responses under a record key of tenant and path.

Frequently asked questions

What does Map.put return in Java?

The value that was previously stored for the key, or null if the key was not present. On maps that allow null values, null can also mean the old value was null.

Can a HashMap have duplicate keys?

No. Putting an existing key replaces its value, and the map's size stays the same. Two keys count as the same when equals returns true and their hash codes match.

How do I add a value only if the key is missing?

Use putIfAbsent(key, value) for a ready-made value, or computeIfAbsent(key, k -> ...) when creating the value is expensive or you need the stored value back.

More examples

Detecting duplicate IDs in a batch

The non-null return value reports the overwrite with no extra lookup. The last write wins, so decide whether that is right for your import or whether a duplicate should reject the batch.

Example · java
record User(String id, String email) {}

void main() {
    List<User> batch = List.of(
            new User("u1", "[email protected]"),
            new User("u2", "[email protected]"),
            new User("u1", "[email protected]"));

    Map<String, User> byId = new LinkedHashMap<>();
    for (User u : batch) {
        User previous = byId.put(u.id(), u);
        if (previous != null) {
            IO.println("duplicate id " + u.id() + ": replaced " + previous.email());
        }
    }
    IO.println(byId.keySet());
    IO.println(byId.get("u1").email());
}
// Output:
// duplicate id u1: replaced [email protected]
// [u1, u2]
// [email protected]

Null handling differs by implementation

Code that works with a HashMap can start throwing when the map is swapped for a TreeMap or ConcurrentHashMap. Keeping nulls out of maps altogether makes such a swap safe.

Example · java
void main() {
    Map<String, String> hash = new HashMap<>();
    hash.put(null, "null key allowed");
    hash.put("note", null);
    IO.println(hash.get(null));
    IO.println(hash.containsKey("note") + " " + hash.get("note"));

    Map<String, String> tree = new TreeMap<>();
    try {
        tree.put(null, "x");
    } catch (NullPointerException e) {
        IO.println("TreeMap: null key rejected");
    }

    Map<String, String> concurrent = new ConcurrentHashMap<>();
    try {
        concurrent.put("note", null);
    } catch (NullPointerException e) {
        IO.println("ConcurrentHashMap: null value rejected");
    }
}
// Output:
// null key allowed
// true null
// TreeMap: null key rejected
// ConcurrentHashMap: null value rejected

A record as a composite key

A new CacheKey with the same components is equal to the stored one because records generate equals and hashCode. With a plain class that did not override them, every lookup would miss.

Example · java
record CacheKey(String tenant, String path) {}

void main() {
    Map<CacheKey, String> cache = new HashMap<>();
    cache.put(new CacheKey("acme", "/products"), "12 products");
    cache.put(new CacheKey("globex", "/products"), "3 products");

    IO.println(cache.get(new CacheKey("acme", "/products")));
    IO.println(cache.size());

    String prev = cache.put(new CacheKey("acme", "/products"), "13 products");
    IO.println("replaced: " + prev);
    IO.println(cache.size());
}
// Output:
// 12 products
// 2
// replaced: 12 products
// 2

Discussion

  • Be the first to comment on this lesson.