HashMap
Java
Programming
Code Initialization
Data Structures

How to directly initialize a HashMap (in a literal way)?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Java does not have a built-in HashMap literal syntax like Python's {"key": "value"}. However, there are several approaches: Map.of() and Map.ofEntries() (Java 9+, immutable), Map.entry() for type-safe entries, double-brace initialization (creates anonymous subclass, generally avoided), and static initializer blocks. For mutable maps, wrap Map.of() with new HashMap<>(Map.of(...)). The recommended approach for Java 9+ is Map.of() for small maps (up to 10 entries) and Map.ofEntries() for larger ones.

java
1import java.util.Map;
2
3// Up to 10 key-value pairs
4Map<String, Integer> scores = Map.of(
5    "Alice", 95,
6    "Bob", 87,
7    "Charlie", 92
8);
9
10System.out.println(scores.get("Alice"));  // 95
11
12// The result is IMMUTABLE
13scores.put("Dave", 88);  // UnsupportedOperationException!

Map.of() creates an unmodifiable map. It supports up to 10 key-value pairs (overloaded methods for 0 to 10 pairs). It does not allow null keys or values, and throws IllegalArgumentException for duplicate keys.

Map.ofEntries() — Java 9+ (More Than 10 Entries)

java
1import java.util.Map;
2import static java.util.Map.entry;
3
4Map<String, String> config = Map.ofEntries(
5    entry("host", "localhost"),
6    entry("port", "5432"),
7    entry("database", "mydb"),
8    entry("user", "admin"),
9    entry("password", "secret"),
10    entry("ssl", "true"),
11    entry("timeout", "30"),
12    entry("pool_size", "10"),
13    entry("retry", "3"),
14    entry("log_level", "INFO"),
15    entry("encoding", "UTF-8")
16    // No limit on number of entries
17);

Map.ofEntries() takes Map.Entry objects and has no limit on the number of entries. Use the static import Map.entry() for concise syntax.

Mutable Map from Map.of()

java
1import java.util.HashMap;
2import java.util.Map;
3
4// Wrap in HashMap for a mutable copy
5Map<String, Integer> mutableMap = new HashMap<>(Map.of(
6    "Alice", 95,
7    "Bob", 87,
8    "Charlie", 92
9));
10
11mutableMap.put("Dave", 88);       // Works!
12mutableMap.remove("Bob");         // Works!
13System.out.println(mutableMap);   // {Alice=95, Charlie=92, Dave=88}

new HashMap<>(Map.of(...)) creates a mutable HashMap initialized with the immutable map's entries. This is the standard pattern for a "HashMap literal" in Java 9+.

Double-Brace Initialization (Avoid)

java
1import java.util.HashMap;
2import java.util.Map;
3
4// Creates an anonymous subclass of HashMap — generally discouraged
5Map<String, Integer> map = new HashMap<String, Integer>() {{
6    put("Alice", 95);
7    put("Bob", 87);
8    put("Charlie", 92);
9}};
10
11// Why avoid:
12// 1. Creates an anonymous inner class (extra .class file)
13// 2. Holds a reference to the enclosing class (memory leak risk)
14// 3. Breaks equals() for some map comparisons
15// 4. Cannot be serialized reliably

Double-brace initialization is concise but creates a hidden anonymous subclass. This causes issues with serialization, equals() comparisons, and memory leaks. Prefer Map.of() or explicit initialization.

Static Initializer Block

java
1import java.util.HashMap;
2import java.util.Map;
3import java.util.Collections;
4
5public class Constants {
6    public static final Map<String, Integer> CODES;
7
8    static {
9        Map<String, Integer> map = new HashMap<>();
10        map.put("OK", 200);
11        map.put("NOT_FOUND", 404);
12        map.put("ERROR", 500);
13        CODES = Collections.unmodifiableMap(map);
14    }
15}
16
17// Usage
18int code = Constants.CODES.get("OK");  // 200

Static initializer blocks are the pre-Java 9 standard for creating constant maps. Collections.unmodifiableMap() wraps the map to prevent modification.

Guava ImmutableMap (Third-Party)

java
1import com.google.common.collect.ImmutableMap;
2
3// Guava's builder pattern
4Map<String, Integer> map = ImmutableMap.of(
5    "Alice", 95,
6    "Bob", 87,
7    "Charlie", 92
8);
9
10// Builder for more entries
11Map<String, Integer> largeMap = ImmutableMap.<String, Integer>builder()
12    .put("Alice", 95)
13    .put("Bob", 87)
14    .put("Charlie", 92)
15    .put("Dave", 88)
16    .build();

Guava's ImmutableMap predates Java 9's Map.of() and offers similar functionality. If your project already uses Guava, this is a fine choice. Otherwise, prefer the standard library.

Java 8 Streams Approach

java
1import java.util.Map;
2import java.util.stream.Collectors;
3import java.util.stream.Stream;
4
5// Stream-based initialization (verbose but flexible)
6Map<String, Integer> map = Stream.of(
7    new Object[]{"Alice", 95},
8    new Object[]{"Bob", 87},
9    new Object[]{"Charlie", 92}
10).collect(Collectors.toMap(
11    e -> (String) e[0],
12    e -> (Integer) e[1]
13));
14
15// Cleaner with AbstractMap.SimpleEntry
16import java.util.AbstractMap;
17
18Map<String, Integer> map2 = Stream.of(
19    new AbstractMap.SimpleEntry<>("Alice", 95),
20    new AbstractMap.SimpleEntry<>("Bob", 87)
21).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

The Stream approach is verbose and not recommended for simple initialization. Use Map.of() or Map.ofEntries() instead.

Comparison Across Languages

java
1// Java 9+
2Map<String, Integer> map = Map.of("a", 1, "b", 2);
3
4// Python
5// map = {"a": 1, "b": 2}
6
7// JavaScript
8// const map = { a: 1, b: 2 };
9// const map = new Map([["a", 1], ["b", 2]]);
10
11// Kotlin
12// val map = mapOf("a" to 1, "b" to 2)
13// val mutableMap = mutableMapOf("a" to 1, "b" to 2)
14
15// C#
16// var map = new Dictionary<string, int> { {"a", 1}, {"b", 2} };

Common Pitfalls

  • Using double-brace initialization in production: It creates an anonymous inner class that holds a reference to the enclosing instance, preventing garbage collection and causing memory leaks in long-lived objects. Use Map.of() or explicit put() calls instead.
  • Trying to modify Map.of() results: Map.of() returns an unmodifiable map. Calling put(), remove(), or clear() throws UnsupportedOperationException. Wrap in new HashMap<>() if you need a mutable map.
  • Passing null to Map.of(): Map.of() and Map.ofEntries() do not allow null keys or values. They throw NullPointerException immediately. If you need null values, use a HashMap with explicit put() calls.
  • Exceeding Map.of() limit: Map.of() supports at most 10 key-value pairs (20 arguments). For more entries, use Map.ofEntries() with entry() calls, which has no limit.
  • Duplicate keys in Map.of(): Map.of("a", 1, "a", 2) throws IllegalArgumentException at runtime. Unlike HashMap.put() which silently overwrites, Map.of() treats duplicate keys as an error. Ensure all keys are unique.

Summary

  • Use Map.of("key", value, ...) for small immutable maps (up to 10 entries, Java 9+)
  • Use Map.ofEntries(entry("key", value), ...) for larger immutable maps
  • Wrap in new HashMap<>(Map.of(...)) when you need a mutable map
  • Avoid double-brace initialization — it creates anonymous subclasses with memory leak risk
  • Use static initializer blocks with Collections.unmodifiableMap() for pre-Java 9 code
  • Map.of() does not allow null keys or values and rejects duplicate keys

Course illustration
Course illustration

All Rights Reserved.