Map.compute recomputes the value associated with a key through a remapping function. A null result removes the mapping, and the method does not distinguish an existing null mapping from an absent key. section 8.4
Null result deletes the entry
var map = new HashMap<String, String>(); map.put("x", null); map.compute("x", (k, v) -> null); System.out.println(map); // {} section 8.4
This makes null a consequential return value rather than an ordinary stored value. Code that intends to preserve an entry must return a non-null value; code that returns null deliberately requests removal. section 8.4
For concurrently updated maps, compute belongs to the Map methods intended to replace non-atomic get-and-put sequences. Use the concurrent map implementation's documented atomic operations rather than reading and writing separately. section 9.12
Avoid these common mistakes:
- Do not infer that a null value means the key is absent; compute treats both situations alike. section 8.4
- Do not use a separate get followed by put when another thread can update the same map entry. section 9.12
- Check whether a null remapping result is an intended deletion before adopting a compute-based update. section 8.4
var map = new HashMap<String, String>();
map.put("x", null);
map.computeIfAbsent("x", k -> null); #1
System.out.println(map); #2
map.compute("x", (k, v) -> null); #3
System.out.println(map); #4
Compare compute with computeIfAbsent when a null mapping already exists; the example isolates how null results affect the map. section 8.4
Table 8.2 Behavior of java.util.Map interface methods with respect to null
|
java.util.Map interface method
|
Distinguishes between existing null mapping and no mapping at all?
|
Puts null mapping if the value parameter is null?
|
Removes existing mapping if lambda returns null?
|
|---|---|---|---|
containsKey
|
yes
|
—
|
—
|
getOrDefault
|
yes
|
—
|
—
|
get
|
no
|
—
|
—
|
put
|
no
|
yes
|
—
|
putIfAbsent
|
no
|
yes
|
—
|
compute
|
no
|
—
|
yes
|
computeIfPresent
|
no
|
—
|
yes
|
computeIfAbsent
|
no
|
—
|
no
|
merge
|
no
|
no
|
yes
|
Use the method table to compare compute with get, put, computeIfPresent, computeIfAbsent, and merge across null-handling behaviors. section 8.4
