Can ConcurrentHashMap have null keys or values? Why not? — Cracked Java
// Java Collections Framework · Concurrent Collections — ConcurrentHashMap
MidTrick

Can ConcurrentHashMap have null keys or values? Why not?

No. ConcurrentHashMap throws NullPointerException on null keys or null values. The reason is ambiguity: in a concurrent context, get(k) == null cannot distinguish "key absent" from "key present, value is null", and there is no atomic containsKey + get to resolve it.

The behavior

ConcurrentHashMap<String, String> m = new ConcurrentHashMap<>();
m.put(null, "x");      // NullPointerException
m.put("x", null);      // NullPointerException
m.putIfAbsent("y", null); // NullPointerException

HashMap allows both: one null key, any number of null values. Hashtable and ConcurrentHashMap forbid both.

The disambiguation argument

With HashMap, the standard "absent vs. null-value" idiom is:

V v = map.get(k);
if (v == null && !map.containsKey(k)) {
    // truly absent
} else if (v == null) {
    // present, value is null
} else {
    // present, value is v
}

This works because nothing modifies the map between get and containsKey. In a concurrent map, another thread could put or remove k between those two calls, making the answer meaningless. Even an atomic containsKey would race with subsequent get.

The CHM designers picked the only sound option: disallow null values entirely. Then get(k) == null unambiguously means "not present".

Why ban null keys too?

Less fundamental — could in principle be allowed — but Doug Lea's rationale (paraphrased from the OpenJDK lists):

  • It avoids special-casing the null key in every hash/equals path.
  • It keeps the API symmetric with the value restriction.
  • It catches a category of bugs early (forgetting to validate input).
  • Hashtable, the predecessor, also banned them.

Real-world implications

// BAD — null-pollution from optional fields
chm.put(user.id, user.profilePictureUrl); // NPE if profilePictureUrl is null

// FIX 1: use Optional
ConcurrentMap<UserId, Optional<URL>> m = new ConcurrentHashMap<>();
m.put(user.id, Optional.ofNullable(user.profilePictureUrl));

// FIX 2: use a sentinel
private static final URL NO_AVATAR = URI.create("about:blank").toURL();
m.put(user.id, user.profilePictureUrl == null ? NO_AVATAR : user.profilePictureUrl);

// FIX 3: just remove the key
if (user.profilePictureUrl == null) m.remove(user.id);
else m.put(user.id, user.profilePictureUrl);

Optional values are the cleanest pattern when "absent in map" and "present-but-null" need to be distinguished.

Other concurrent maps with the same restriction

MapNull keys?Null values?
HashMap, LinkedHashMapyes (1)yes
TreeMapno (NPE in Comparator)yes
Hashtablenono
ConcurrentHashMapnono
ConcurrentSkipListMapnono

All concurrent maps in java.util.concurrent ban nulls — same reasoning.

What getOrDefault does

chm.getOrDefault("missing", "fallback");  // returns "fallback"

This is the cleanest way to "return X if not present" — unambiguous because the default is non-null.

Mark your status