Initialize a HashMap in Java

1. Overview

In this tutorial, we’ll learn about various ways of initializing a HashMap in Java.

We’ll use Java 8 as well as Java 9.

2. The Static Initializer for a Static HashMap

We can initialize a HashMap using a static block of code:

public static Map<String, String> articleMapOne;
static {
    articleMapOne = new HashMap<>();
    articleMapOne.put("ar01", "Intro to Map");
    articleMapOne.put("ar02", "Some article");
}

The advantage of this kind of initialization is that the map is mutable, but it will only work for static. Consequently, entries can be added and removed as and when required.

Let’s go ahead and test it:

@Test
public void givenStaticMap_whenUpdated_thenCorrect() {
    
    MapInitializer.articleMapOne.put(
      "NewArticle1", "Convert array to List");
    
    assertEquals(
      MapInitializer.articleMapOne.get("NewArticle1"), 
      "Convert array to List");  
}

We can also initialize the map using the double-brace syntax:

Map<String, String> doubleBraceMap  = new HashMap<String, String>() {{
    put("key1", "value1");
    put("key2", "value2");
}};

Note that we must try to avoid this initialization technique because it creates an anonymous extra class at every usage, holds hidden references to the enclosing object, and might cause memory leak issues.

3. Using Java Collections

If we need to create a singleton immutable map with a single entry, Collections.singletonMap() becomes very useful:

public static Map<String, String> createSingletonMap() {
    return Collections.singletonMap("username1", "password1");
}

Note that the map here is immutable, and if we try to add more entries, it’ll throw java.lang.UnsupportedOperationException.

We can also create an immutable empty map by using Collections.emptyMap():

Map<String, String> emptyMap = Collections.emptyMap();

4. The Java 8 Way

In this section, let’s look into the ways to initialize a map using Java 8 Stream API.

4.1. Using Collectors.toMap()

Let’s use a Stream of a two-dimensional String array and collect them into a map:

Map<String, String> map = Stream.of(new String[][] {
  { "Hello", "World" }, 
  { "John", "Doe" }, 
}).collect(Collectors.toMap(data -> data[0], data -> data[1]));

Notice here the data type of key and value of the Map is the same.

In order to make it more generic, let’s take the array of Objects and perform the same operation:

Map<String, Integer> map = Stream.of(new Object[][] { 
     { "data1", 1 }, 
     { "data2", 2 }, 
 }).collect(Collectors.toMap(data -> (String) data[0], data -> (Integer) data[1]));

As a result, we create a map of the key as a String and value as an Integer.

4.2. Using a Stream of Map.Entry

Here we’ll use the instances of Map.Entry. This is another approach where we have different key and value types.

First, let’s use SimpleEntry implementation of the Entry interface:

Map<String, Integer> map = Stream.of(
  new AbstractMap.SimpleEntry<>("idea", 1), 
  new AbstractMap.SimpleEntry<>("mobile", 2))
  .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

Now let’s create the map using SimpleImmutableEntry implementation:

Map<String, Integer> map = Stream.of(
  new AbstractMap.SimpleImmutableEntry<>("idea", 1),    
  new AbstractMap.SimpleImmutableEntry<>("mobile", 2))
  .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

4.3. Initializing an Immutable Map

In certain use cases, we need to initialize an immutable map. This could be done by wrapping the Collectors.toMap() inside Collectors.collectingAndThen():

Map<String, String> map = Stream.of(new String[][] { 
    { "Hello", "World" }, 
    { "John", "Doe" },
}).collect(Collectors.collectingAndThen(
    Collectors.toMap(data -> data[0], data -> data[1]), 
    Collections::<String, String> unmodifiableMap));

Note that we should avoid using such initialization using Streams, as it could cause a huge performance overhead and lots of garbage objects are created just to initialize the map.

5. The Java 9 Way

Java 9 comes with various factory methods in the Map interface that simplify the creation and initialization of immutable maps.

Let’s go ahead and look into these factory methods.

5.1. Map.of()

This factory method takes no argument, a single argument, and variable arguments:

Map<String, String> emptyMap = Map.of();
Map<String, String> singletonMap = Map.of("key1", "value");
Map<String, String> map = Map.of("key1","value1", "key2", "value2");

Note that this method supports only a maximum of 10 key-value pairs.

5.2. Map.ofEntries()

It’s similar to the Map.of() but has no limitations on the number of key-value pairs:

Map<String, String> map = Map.ofEntries(
  new AbstractMap.SimpleEntry<String, String>("name", "John"),
  new AbstractMap.SimpleEntry<String, String>("city", "budapest"),
  new AbstractMap.SimpleEntry<String, String>("zip", "000000"),
  new AbstractMap.SimpleEntry<String, String>("home", "1231231231")
);

Note that the factory methods produce immutable maps, hence any mutation will result in a UnsupportedOperationException.

Also, they do not allow null keys or duplicate keys.

Now if we need a mutable or growing map after initialization, we can create any of the implementations of the Map interface and pass these immutable maps in the constructor:

Map<String, String> map = new HashMap<String, String> (
  Map.of("key1","value1", "key2", "value2"));
Map<String, String> map2 = new HashMap<String, String> (
  Map.ofEntries(
    new AbstractMap.SimpleEntry<String, String>("name", "John"),    
    new AbstractMap.SimpleEntry<String, String>("city", "budapest")));

6. Using Guava

As we’ve looked into the ways of using core Java, let’s move ahead and initialize a map using the Guava library:

Map<String, String> articles 
  = ImmutableMap.of("Title", "My New Article", "Title2", "Second Article");

This would create an immutable map, and to create a mutable one:

Map<String, String> articles 
  = Maps.newHashMap(ImmutableMap.of("Title", "My New Article", "Title2", "Second Article"));

The method ImmutableMap.of() also has overloaded versions that can take up to 5 pairs of key-value parameters. Here’s what an example with 2 pairs of parameters would look like:

ImmutableMap.of("key1", "value1", "key2", "value2");

7. Conclusion

In this article we explored the various ways of initializing a Map, particularly to create empty, singleton, immutable and mutable maps. As we can see, there’s a huge improvement in this field since Java 9. 

Related posts:

Spring Boot Application as a Service
Spring Boot - Introduction
Java Program to Perform integer Partition for a Specific Case
Java Program to Implement the Checksum Method for Small String Messages and Detect
Running Spring Boot Applications With Minikube
Biểu thức Lambda trong Java 8 – Lambda Expressions
Send email with authentication
New Features in Java 15
Working With Maps Using Streams
Jackson – Change Name of Field
Java Program to Implement Sorted Circular Doubly Linked List
Java Program to Implement String Matching Using Vectors
A Guide to Java HashMap
Java Program to Implement Sorting of Less than 100 Numbers in O(n) Complexity
Custom Error Pages with Spring MVC
Java Program to Generate All Possible Combinations Out of a, b, c, d, e
How to Remove the Last Character of a String?
Java Program to Implement CopyOnWriteArraySet API
Java Program to implement Associate Array
Quick Guide to the Java StringTokenizer
So sánh HashSet, LinkedHashSet và TreeSet trong Java
Examine the internal DNS cache
Hướng dẫn sử dụng luồng vào ra nhị phân trong Java
Java Program to Implement Max Heap
Java Program to Generate a Graph for a Given Fixed Degree Sequence
Java Program to Implement Levenshtein Distance Computing Algorithm
Java Program to Implement Efficient O(log n) Fibonacci generator
Java Program to Perform Postorder Non-Recursive Traversal of a Given Binary Tree
Multi Dimensional ArrayList in Java
LinkedHashSet trong java
Spring WebClient and OAuth2 Support
Java Program to Implement Binary Tree