Map.of()
Create a small unmodifiable map in one expression, and know why it rejects nulls, duplicate keys and any later change.
static <K, V> Map<K, V> of(K k1, V v1, ..., K k10, V v10)- Added in Java Java 9
Parameters
| Parameter | Type | Description |
|---|---|---|
$k1optional | K | The first key. Must not be null. |
$v1optional | V | The value for k1. Must not be null. |
$k2 ... v10optional | K, V | Further keys and values in pairs, up to ten pairs in total. Use Map.ofEntries for more. |
Return value
Map<K, V>An unmodifiable map containing the given mappings. There are overloads for zero to ten key-value pairs.
Errors
IllegalArgumentException if any two keys are equal; NullPointerException if any key or value is null. Every mutating method on the result throws UnsupportedOperationException.
Map.of builds an unmodifiable map from keys and values written in pairs: Map.of("free", 60, "team", 600). It arrived in Java 9 and replaced the old routine of creating a HashMap, calling put a few times and wrapping it in Collections.unmodifiableMap.
There are overloads for zero to ten pairs. Keys and values alternate, so there is no varargs version. For more than ten entries use Map.ofEntries(Map.entry(k, v), ...), which takes any number of entries.
What it refuses
- Duplicate keys throw
IllegalArgumentExceptionwhen the map is created. A lookup table with a copy-and-paste mistake fails at startup instead of silently keeping one of the values. - Null keys and null values throw
NullPointerException. If a value comes from an environment variable that is not set,Map.offails on the spot. - Changes after creation.
put,remove,merge,clearand the other mutators throwUnsupportedOperationException. The map is only shallowly immutable: a mutable object stored as a value can still be changed. - Null queries.
get(null)andcontainsKey(null)throwNullPointerExceptionrather than returning null or false. Check a request parameter for null before using it as a key.
Iteration order is not yours to rely on
The iteration order of Map.of is unspecified and can change from one run of the JVM to the next. Code that prints such a map, serialises it to JSON or compares its toString() in a test can pass once and fail later. When order matters, copy into a TreeMap for sorted keys or build a LinkedHashMap for insertion order.
Of, copyOf and unmodifiableMap
Map.copyOf (Java 10) takes a snapshot of an existing map with the same rules. Collections.unmodifiableMap is different: it is a read-only view, so later changes to the underlying map show through it. Return Map.copyOf(internal) from a service when callers must not see later updates.
On the back end Map.of suits fixed tables: status codes to reason phrases, file extensions to content types, default headers and test fixtures.
Example
When to use it
- Mapping HTTP status codes to reason phrases in an error response builder.
- Declaring a fixed table of file extensions to content types for a static file handler.
- Building small fixture maps of request parameters for unit tests of a service method.
Frequently asked questions
How many entries can Map.of take?
Up to ten key-value pairs; there is an overload for each count from zero to ten. For more, use Map.ofEntries(Map.entry(k, v), ...), which accepts any number of entries.
Why does Map.of throw NullPointerException?
Maps built by Map.of do not allow null keys or values, and they also throw when you query them with a null key, for example get(null) or containsKey(null). Leave the entry out instead of storing null, or use a HashMap if you really need null.
Does Map.of keep insertion order?
No. Its iteration order is unspecified and can change between JVM runs. Use a LinkedHashMap for insertion order or a TreeMap for sorted keys.
More examples
Duplicate keys and nulls fail at creation
All three mistakes fail fast with an exception instead of producing a map that quietly holds the wrong data. The containsKey(null) case surprises people who are used to HashMap, which simply answers false.
void main() {
try {
Map.of("timeout", 30, "retries", 3, "timeout", 60);
} catch (IllegalArgumentException e) {
IO.println("IllegalArgumentException: " + e.getMessage());
}
String region = null; // for example, an environment variable that is not set
try {
Map.of("region", region);
} catch (NullPointerException e) {
IO.println("NullPointerException: null value");
}
try {
Map.of("page", "1").containsKey(null);
} catch (NullPointerException e) {
IO.println("NullPointerException: containsKey(null)");
}
}
// Output:
// IllegalArgumentException: duplicate key: timeout
// NullPointerException: null value
// NullPointerException: containsKey(null)More than ten entries with Map.ofEntries
Map.of stops at ten pairs, so an eleventh entry needs Map.ofEntries. A static import of Map.entry keeps the table readable.
import static java.util.Map.entry;
void main() {
Map<String, String> contentTypes = Map.ofEntries(
entry("html", "text/html"),
entry("css", "text/css"),
entry("js", "text/javascript"),
entry("json", "application/json"),
entry("xml", "application/xml"),
entry("png", "image/png"),
entry("jpg", "image/jpeg"),
entry("gif", "image/gif"),
entry("svg", "image/svg+xml"),
entry("pdf", "application/pdf"),
entry("txt", "text/plain"));
IO.println(contentTypes.size());
IO.println(contentTypes.get("json"));
IO.println(contentTypes.getOrDefault("exe", "application/octet-stream"));
}
// Output:
// 11
// application/json
// application/octet-streamA snapshot with Map.copyOf versus a view
The unmodifiable view follows every later change to the map behind it, while Map.copyOf took a copy at that moment. Use copyOf when handing configuration to other code that must not see later edits.
void main() {
Map<String, Integer> limits = new HashMap<>();
limits.put("free", 100);
limits.put("team", 1000);
Map<String, Integer> view = Collections.unmodifiableMap(limits);
Map<String, Integer> snapshot = Map.copyOf(limits);
limits.put("enterprise", 10000);
IO.println("view sees: " + view.size());
IO.println("snapshot sees: " + snapshot.size());
IO.println(snapshot.containsKey("enterprise"));
}
// Output:
// view sees: 3
// snapshot sees: 2
// false
Discussion