Initialize Map with Values in Java
In this tutorial, we’ll learn different ways to initialize a Map with values in Java.
Using Map.of() and Map.ofEntries()
It is possible to initialize a Map with values in a single expression if you are using Java 9 or higher version using Map.of()
and Map.ofEntries()
method. This is shortest possible way so far.
Map.of()
Java 9 provides mutiple Map.of()
overloaded methods to initialize a Map
with upto 10 key-value pairs.
Map<String, Integer> emptyMap = Map.of();
Map<String, Integer> singletonMap = Map.of("A", 1);
Map<String, Integer> map = Map.of("A", 1, "B", 2, "C", 3);
Map.ofEntries()
If you have more than 10 key-value pairs to initialize, then you should use Map.ofEntries()
method. This method has no limit and you can define any number of key-value pairs.
Map<String, Integer> map = Map.ofEntries(
Map.entry("A", 1),
Map.entry("B", 2),
Map.entry("C", 3),
Map.entry("D", 4),
Map.entry("E", 5),
Map.entry("F", 6),
Map.entry("G", 7),
Map.entry("H", 8),
Map.entry("I", 9),
Map.entry("J", 10),
Map.entry("K", 11),
Map.entry("L", 12)
);
map.put("M", 13); // Throw UnsupportedOperationException
map.remove("A"); // Throw UnsupportedOperationException
Mutable Map
Thing to note that both Map.of()
and Map.ofEntries()
return an immutable map which means that adding or removing an element in Map
result into java.lang.UnsupportedOperationException
exception.
You can avoid this by creating a mutable map (by copying the immutable map to new HashMap
) in this way:-
Map<String, Integer> mutableEmptyMap = new HashMap<>(Map.of());
Map<String, Integer> mutableSingletonMap = new HashMap<>(Map.of("A", 1));
Map<String, Integer> mutableMap = new HashMap<>(Map.ofEntries(
Map.entry("A", 1),
Map.entry("B", 2),
Map.entry("C", 3),
Map.entry("D", 4),
Map.entry("E", 5),
Map.entry("F", 6),
Map.entry("G", 7),
Map.entry("H", 8),
Map.entry("I", 9),
Map.entry("J", 10),
Map.entry("K", 11),
Map.entry("L", 12)
));
mutableMap.put("M", 13); // It works!
mutableMap.remove("A"); // It works!
Using Java Collections
Java Collections
class provide methods to initialize emptyMap()
, singletonMap()
and unmodifiableMap()
. Note that all these methods return immutable map
Map<String, Integer> emptyMap = Collections.emptyMap();
Map<String, Integer> singletonMap = Collections.singletonMap("A", 1);
singletonMap.put("B", 2); // Throw UnsupportedOperationException
singletonMap.remove("A"); // Throw UnsupportedOperationException
Map<String, Integer> mutableMap = new HashMap<>(singletonMap);
mutableMap.put("B", 2); // It works!
Map<String, Integer> immutableMap = Collections.unmodifiableMap(mutableMap);
immutableMap.put("B", 2); // Throw UnsupportedOperationException
Initialize Map as an instance variable
If you initialize a Map
as an instance variable, keep the initialization in a constructor or instance initializer:-
public class MyClass {
Map<String, Integer> instanceMap = new HashMap<>();
{
instanceMap.put("A", 1);
instanceMap.put("B", 2);
}
}
Initialize Map as a static variable
If you initialize a Map
as a static class variable, keep the initialization in a static initializer:-
public class MyClass {
static Map<String, Integer> staticMap = new HashMap<>();
static{
staticMap.put("A", 1);
staticMap.put("B", 2);
}
}
Using Double Brace Initialization
You can initialize map with values using Double Brace Initialization:-
Map<String, Integer> map = new HashMap<>() {{
put("A", 1);
put("B", 2);
}};
In Double brace initialization {{ }}
, first brace creates a new Anonymous Inner Class, the second brace declares an instance initializer block that is run when the anonymous inner class is instantiated.
This approach is not recommended as it creates an extra class at each usage. It also holds hidden references to the enclosing instance and any captured objects. This may cause memory leaks or problems with serialization.
The alternative approach for this is to create a function to initialize a map:-
// It works for all Java versions, mutable map.
Map<String, Integer> map = createMap();
map.put("C", "3"); // It works!
private static Map<String, String> createMap() {
Map<String, Integer> map = new HashMap<>();
map.put("A", 1);
map.put("B", 2);
return map;
}
Using Stream Collectors.toMap()
We can also use Java 8 Stream
API to initialize a Map
with values.
When both key and value are of same type (e.g. String):-
Map<String, String> mutableMap1 = Stream.of(new String[][]{
{"A", "a"},
{"B", "b"},
{"C", "c"}
}).collect(Collectors.toMap(p -> p[0], p -> p[1]));
When both key and value are of different type (e.g. String and Integer):-
Map<String, Integer> mutableMap2 = Stream.of(new Object[][]{
{"A", 1},
{"B", 2},
{"C", 3}
}).collect(Collectors.toMap(p -> (String) p[0], p -> (Integer) p[1]));
Another approach that can easily accommodate different types for key and value involves creating a stream of map entries.
Map<String, Integer> mutableMap3 = Stream.of(
new AbstractMap.SimpleEntry<>("A", 1),
new AbstractMap.SimpleEntry<>("B", 2),
new AbstractMap.SimpleEntry<>("C", 3))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
Map<String, Integer> mutableMap4 = Stream.of(
new AbstractMap.SimpleImmutableEntry<>("A", 1),
new AbstractMap.SimpleImmutableEntry<>("B", 2),
new AbstractMap.SimpleImmutableEntry<>("C", 3))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
The only difference between SimpleEntry
and SimpleImmutableEntry
is that you can set the value of SimpleEntry
instance once initialized whereas set value of SimpleImmutableEntry
after initialization throw UnsupportedOperationException
.
Note that all the maps we have initialized using streams so far are mutable map means we can add or remove elements from them. You can initialize an immutable map using streams in this way:-
Map<String, Integer> map5 = Stream.of(
new AbstractMap.SimpleEntry<>("A", 1),
new AbstractMap.SimpleEntry<>("B", 2),
new AbstractMap.SimpleEntry<>("C", 3))
.collect(Collectors.collectingAndThen(
Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue),
Collections::unmodifiableMap
));
Conclusion
Let’s look at the summary of all the ways to initialize a Map with values:-
- Using Map.of() and Map.ofEntries() – Recommended this single line expression if you use Java 9 and above
- Using Java Collections – Works with all Java versions. Useful to define singleton map upto Java 8
- Using Double Brace Initialization - Avoid Double braces initialization. Create a method instead.
- Initialize Map as an instance variable - Recommended to initialize instance variable
- Initialize Map as a static variable - Recommended to initialize static variable
- Using Stream Collectors.toMap() – Too many lines of code. We can use other alternatives if possible to avoid boilerplate code.