Back to Blog
Java

Java Map.copyOf: Creating Immutable Map Copies

java map copyof: Learn how to use Map.copyOf to create immutable map copies in Java, including null handling, performance, and version requirements.

Map.copyOfImmutable MapJava CollectionsJava 10Null Handling
Illustration of copying a Java map to an immutable map using Map.copyOf.

Java map copyof is a common operation when you need an immutable snapshot of an existing map. The standard API for this is Map.copyOf, introduced in Java 10. It returns a new map that contains the same entries as the source, but with no dependency on the original after creation.

Basic Usage and Syntax

The simplest form takes an existing map and returns a new immutable map:

Map<String, Integer> original = new HashMap<>(); original.put("apple", 1); original.put("banana", 2); Map<String, Integer> copy = Map.copyOf(original);

The returned map is not a view; it is a separate object. Changes made to original after the copy is created do not affect copy, and vice versa. The method also works with any Map implementation, including LinkedHashMap, TreeMap, or custom implementations.

There is also a varargs overload that accepts alternating key-value pairs:

Map<String, Integer> another = Map.ofEntries( Map.entry("apple", 1), Map.entry("banana", 2) );

But Map.copyOf specifically takes a Map argument, not varargs. The Map.of and Map.ofEntries methods create immutable maps directly, but they do not copy from an existing map.

Immutability and Behavior

The map returned by Map.copyOf is structurally immutable. Any attempt to modify it—whether by put, remove, clear, or through an iterator's remove method—throws UnsupportedOperationException. This is a stronger guarantee than Collections.unmodifiableMap, which still allows the underlying map to change if it is modified elsewhere.

Because the copy is immutable, it is safe to share across threads without additional synchronization. The map also does not permit null keys or null values. If the source map contains a null key or value, Map.copyOf throws NullPointerException. This is consistent with the behavior of Map.of and Map.ofEntries.

The iteration order of the returned map is unspecified. If you need a predictable order, use a LinkedHashMap as the source and copy it with Map.copyOf, but the order is not guaranteed by the method itself. In practice, the iteration order often follows the source map's order, but you should not rely on it.

Null Handling and Exceptions

Map.copyOf rejects null keys and null values. The exception is thrown eagerly when the method is called, not when the map is later accessed. This makes it a good choice for defensive copying when you want to fail fast on invalid input.

Consider this example:

Map<String, String> withNull = new HashMap<>(); withNull.put("key", null); try { Map.copyOf(withNull); } catch (NullPointerException e) { System.out.println("Cannot copy a map with null values"); }

The same applies to null keys. If you need to allow nulls, you must use a different approach, such as Collections.unmodifiableMap(new HashMap<>(original)), which does not perform null checks. However, that approach only creates an unmodifiable view, not a true copy, and the underlying map remains mutable.

Comparing Map.copyOf with Other Copy Techniques

There are several ways to create a copy of a map in Java, and each has different semantics. The table below summarizes the key differences:

MethodImmutable?Null keys/values allowed?Copies entries?Java version
Map.copyOf(map)YesNoYes10+
new HashMap<>(map)NoYesYesAll
Collections.unmodifiableMap(map)View onlyDepends on underlying mapNo1.2+
Map.ofEntries(...)YesNoCreates new9+

new HashMap<>(map) creates a mutable copy that allows nulls, but it is not immutable. Collections.unmodifiableMap(map) wraps the original map, so changes to the original are visible through the unmodifiable view. Map.ofEntries is useful when you are constructing a map from scratch, not copying an existing one.

For most defensive-copy scenarios, Map.copyOf is the right choice when you want an immutable snapshot and you are sure the source contains no nulls.

Performance and Memory Characteristics

Map.copyOf creates a new map and copies all entries. The time complexity is O(n), where n is the number of entries. The memory footprint is proportional to the number of entries, and the copy does not share internal structures with the source. This is different from Collections.unmodifiableMap, which is O(1) to create but does not copy data.

Because the returned map is immutable, it can be safely cached and reused. There is no risk of accidental modification, which simplifies reasoning about shared state in concurrent applications. However, the copy itself requires allocation and entry copying, so for very large maps, consider whether a full copy is necessary. If you only need a read-only view and can guarantee the source map will not change, Collections.unmodifiableMap may be more efficient.

Version and Compatibility Considerations

Map.copyOf was introduced in Java 10. If you are working with Java 8 or 9, you need an alternative. The most common workaround is to combine Collections.unmodifiableMap with a copy constructor:

Map<String, Integer> copy = Collections.unmodifiableMap(new HashMap<>(original));

This creates a mutable copy and then wraps it, but the result is not truly immutable because the underlying map can still be modified if you keep a reference to the HashMap. A more defensive approach is to create a new HashMap and then use Collections.unmodifiableMap, but you must ensure the original is not modified after the copy.

For Java 9, you can use Map.ofEntries with a stream, but that is less direct. If you are on Java 10 or later, Map.copyOf is the cleanest and most idiomatic solution.

Edge Cases and Practical Tips

One common mistake is assuming Map.copyOf preserves the iteration order of a LinkedHashMap. It does not guarantee any order. If order matters, you should explicitly copy into a LinkedHashMap and then wrap it, but that loses the immutability guarantee. Alternatively, you can use Collections.unmodifiableMap(new LinkedHashMap<>(original)) if you need both order and a read-only view, but again, the underlying map is mutable.

Another edge case involves copying a map that is already immutable. Map.copyOf will still create a new copy, which is redundant but harmless. If you are frequently copying the same map, consider caching the copy.

When working with custom key or value objects, ensure they are properly immutable themselves. The map's immutability does not extend to the objects it contains. If a value object is mutable, changes to that object are still possible through the map reference.

Finally, remember that Map.copyOf does not accept null entries. If you are copying a map that may contain nulls, you must filter them or use a different copy method. A common pattern is to use Map.copyOf only after validating the source.

java map copyof: How to Create Immutable Maps | RYUSLOG DEV