Skip to content
All Posts

ImmutableMap Does Not Allow null

An explanation of Guava ImmutableMap's null restrictions and the tradeoffs of alternative immutable map wrappers.

Example

I found code like this in a project:

Map tmpParams = ImmutableMap.of(
"extraInfos", ext.get("extraInfos"),
"otherParams", ImmutableMap.builder()
.put("version", 0)
.put("orderId", MapUtils.getString(ext, "orderId"));

It occasionally raised an NPE because the value associated with orderId was null. ImmutableMap permits neither null keys nor null values.

Guava’s GitHub repository has a discussion of null values. The official recommendation is to wrap them with Optional; avoiding null also makes inline and stream operations easier. Other Guava components, including LoadingCache, likewise reject null.

If you need an immutable map that permits null, you can use:

Map<String, String> testMap = new HashMap<>();
testMap.put("a", "1");
Map<String, String> immutableMap =
Collections.unmodifiableMap(new HashMap<>(testMap));

Keys and values cannot be replaced through this map, although fields inside a mutable value object can still be changed.

Summary

Good uses for ImmutableMap:

  1. Deterministic configuration, such as mapping keys to request URLs.
  2. Unit tests.

Poor uses:

  1. Unknown keys or values that may be null.

One practical point

With a HashMap, this code would not have failed. Tool classes have their own constraints; if you do not know them, cases like this can be surprising.


Originally published on SegmentFault.