Updating is just put with an existing key
A HashMap holds at most one value per key. When you call put with a key that is already in the map, Java doesn't add a second entry. It overwrites the old value with the new one.
HashMap<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.put("Bob", 87);
scores.put("Alice", 99); // update: Alice is now 99
scores.put("Charlie", 72); // add a new entry
The same method both inserts and updates. Whether the call adds or changes depends only on whether the key is already there. After the code above the map has three entries, and scores.get("Alice") is 99. The size grows only for Charlie.
What put returns
The method returns the previous value for that key, or null when the key was new. You usually ignore it, but it tells you what happened:
System.out.println(scores.put("Alice", 100)); // 99, the old value
System.out.println(scores.put("Zed", 1)); // null, a new key
This works because put is an expression with a value, like any method call that returns something, and a statement that ignores the value is perfectly legal.
Updating only when the key exists
Sometimes you want a change to apply only to a key that is already present, and you don't want a typo to create a new entry. That is what replace does:
scores.replace("Alice", 99); // updates, because Alice exists
scores.replace("Nobody", 5); // does nothing, no entry is created
System.out.println(scores.containsKey("Nobody")); // false
Like put, it returns the old value, or null if the key was missing.
Computing the new value from the old one
Many updates depend on the current value, such as adding points. Read it, change it, and store it back:
scores.put("Bob", scores.get("Bob") + 5);
This works when the key exists. If it might not, scores.get("Bob") would be null, and adding 5 to it throws a NullPointerException. Use getOrDefault in that case: scores.put("Bob", scores.getOrDefault("Bob", 0) + 5). Another option is merge, which does the whole thing in one call: scores.merge("Bob", 5, Integer::sum) stores 5 for a missing key and adds 5 to the existing value otherwise.
Updating every value
To change all the values at once, loop over the keys and put each new value back. Overwriting existing keys while looping is safe:
for (String k : scores.keySet()) {
scores.put(k, scores.get(k) + 1);
}
If the scores were 95 and 87, they are now 96 and 88. The map offers a shorter form too. replaceAll takes a function from key and value to the new value, so scores.replaceAll((k, v) -> v + 10) adds 10 to every entry. Both approaches leave the number of entries as it was.
The lesson's exercise
The starting code has a map with two entries:
HashMap<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.put("Bob", 87);
The task has one step: set Alice's score to 99. Below the map, call scores.put("Alice", 99). Because "Alice" is already a key, the call replaces 95 with 99 instead of adding anything, and Bob's entry is untouched. The map still has two entries.
The complete code is:
HashMap<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.put("Bob", 87);
scores.put("Alice", 99);
Gotchas
- Keys are case-sensitive.
scores.put("alice", 99)doesn't update Alice. It creates a separate entry for"alice"and leaves the original value at 95. - Typos silently add entries. With
put, a misspelled key just becomes a new key. When you mean to update,replaceis safer. - The old value is gone. After overwriting, the previous value is not stored anywhere in the map. Save it first, or use the return value of
put, if you still need it. - Don't change a map while looping over it. Adding or removing entries inside a loop over
keySet()orentrySet()can throw aConcurrentModificationException. Overwriting the value of an existing key is allowed, because that doesn't change the map's structure.
Key takeaways
put(key, value)adds a new entry or overwrites the value of an existing key.replace(key, value)updates only when the key already exists.- Both return the old value, or
nullif there was none. - For updates based on the current value, use
getOrDefaultormergeto cover missing keys.