The result of an initialized HashMap is a mutable map or an immutable map:
- Mutable map : in this case we can modify the Map entries.
- Immutable map : in this case we can’t add or modify the Map entries, and if we modify it, it throws UnsupportedOperationException.
To initialize a HashMap , there are many ways :
1. The Standard way:
// normal way, mutable map
Map<String, String> map = new HashMap<>();
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
System.out.println(map.getClass()); // java.util.HashMap
// convert mutable Map to immutable map
Map<String, String> immutableMap = Collections.unmodifiableMap(map);
System.out.println(immutableMap.getClass()); // java.util.Collections$UnmodifiableMap
immutableMap.put("key4", "value4"); // UnsupportedOperationException
2. Using Collections.singletonMap
In this example we will use Collections.singletonMap to initialize a single entry SingletonMap, witch give an immutable map.
// @since 1.3
// single entry immutable map
Map<String, String> map = Collections.singletonMap("key1", "value1");
System.out.println(map.getClass()); // java.util.Collections$SingletonMap
map.put("key2", "value2"); // throws UnsupportedOperationException
3. In Java 9 by using Map.of
Java 9 introduced a new way to initialize a HashMap , Map.of returns an immutable map containing up to 10 entries.
// Java 9, max is 10 entries or elements, immutable map
Map<String, String> map = Map.of(
"key1", "value1",
"key2", "value2",
"key3", "value3"
);
System.out.println(map.getClass()); // java.util.ImmutableCollections$MapN
map.put("key3", "value4"); // throws UnsupportedOperationException
Review the Java 9 source code of Map.java. They created 10 Map.of overloading methods to initialize a Map containing up to 10 entries or elements.
static <K, V> Map<K, V> of(K k1, V v1) {
return new ImmutableCollections.Map1<>(k1, v1);
}
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2) {
return new ImmutableCollections.MapN<>(k1, v1, k2, v2);
}
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) {
return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3);
}
// up to 10 elements...
4. Java 9 Map.ofEntries
Java 9 introduced a similar API, Map.ofEntries, which returns an unmodifiable or immutable map, but this Map has no limit of the Map entry, and we can create as many entries as we want.
// Java 9, no limit of Map entry, immutable map.
Map<String, String> map = Map.ofEntries(
Map.entry("key1", "value1"),
Map.entry("key2", "value2"),
Map.entry("key3", "value3")
);
System.out.println(map.getClass()); // java.util.ImmutableCollections$MapN
map.put("key4", "value4"); // throws UnsupportedOperationException
5. Create a function to return a Map
We can create a function to initialize a HashMap, which works for all Java versions. The function returns a mutable map.
// It works for all Java versions, mutable map.
Map<String, String> map = createMap();
System.out.println(map.getClass()); // java.util.HashMap
map.put("key4", "value4"); // yes, we can do it
private static Map<String, String> createMap() {
Map<String, String> map = new HashMap<>();
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
return map;
}
6. Static Initializer
This solution is for a static Map variable, and it returns a mutable map.
public static Map<String, String> map;
static {
// mutable map
map = new HashMap<>();
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
}
7. Java 8, Stream of SimpleEntry
This example creates a stream of SimpleEntry and returns a mutable map. Do not use the below method to initialize a HashMap, I don’t see any benefits of a stream of SimpleEntry, error-prone and ugly syntax, just for reference.
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
import static java.util.stream.Collectors.toMap;
//...
// mutable map
Map<String, String> map = Stream.of(
new AbstractMap.SimpleEntry<>("key1", "value1"),
new AbstractMap.SimpleEntry<>("key2", "value2"),
new AbstractMap.SimpleEntry<>("key3", "value3"))
.collect(
toMap(AbstractMap.SimpleEntry::getKey,
AbstractMap.SimpleEntry::getValue)
);
System.out.println(map.getClass()); // java.util.HashMap
map.put("key4", "value4"); // no problem.