Java Maps
by Fossery Tech
Download (.odt) Download (Markdown)Map implementations
HashMap: best performance for basic operations like get() and put(), one null key allowed, no fix order for entries
LinkedHashMap: worse performance, but fix order for entries
TreeMap: keys are sorted in natural order or by a custom Comparator, no null keys allowed
ConcurrentHashMap: thread-safe version of HashMap, no null keys and values allowed
EnumMap: for enum keys, good performance
WeakHashMap: holds keys via weak references, removes entries when keys are no longer strongly reachable, useful for caches
Code blocks in this cheatsheet use HashMap, but most operations work with all other Map implementations too.
Define a Map
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores = new HashMap<>();
Define an immutable Map with no entry:
import java.util.Map;
import java.util.Collections;
Map<String, Integer> scores = Collections.emptyMap();
Define an immutable Map with only one entry:
import java.util.Map;
import java.util.Collections;
Map<String, Integer> scores = Collections.singletonMap("Alice", 12);
Define an immutable Map with a maximum of 10 entries:
import java.util.Map;
Map<String, Integer> scores = Map.of(
"Alice", 12,
"Bob", 34,
"Charlie", 23,
"Daniel", 35,
"Ellie", 54
);
Define an immutable Map with any number of entries:
import java.util.Map;
Map<String, Integer> scores = Map.ofEntries(
Map.entry("Alice", 12),
Map.entry("Bob", 34),
Map.entry("Charlie", 23),
Map.entry("Daniel", 35),
Map.entry("Ellie", 54)
);
Define a synchronized (thread-safe) map based on a Map implementation (e.g. HashMap):
import java.util.HashMap;
import java.util.Map;
import java.util.Collections;
Map<String, Integer> scores = Collections.synchronizedMap(new HashMap<>());
Define a synchronized (thread-safe) map based on a SortedMap implementation (e.g. TreeMap):
import java.util.TreeMap;
import java.util.Map;
import java.util.Collections;
Map<String, Integer> scores = Collections.synchronizedSortedMap(new TreeMap<>());
Add entry/entries to a Map
Add a single entry:
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
Add a single entry only if there isn't an entry yet with the same key:
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.putIfAbsent("Alice", 67);
// "Alice" is still associated with 95
Add a key with the result of a specified operation as value:
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.compute("Alice", (key, value) -> key.length());
// `scores` becomes {Alice=5} (because the length of "Alice" is calculated to be 5)
scores.compute("Bob", (key, value) -> key.length());
// `scores` becomes {Bob=3, Alice=5}
Add a key with the result of a specified operation as value, only if there's already an entry with the specified key:
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.computeIfPresent("Alice", (key, value) -> key.length());
// `scores` becomes {Alice=5} (because the length of "Alice" is calculated to be 5)
scores.computeIfPresent("Bob", (key, value) -> key.length());
// `scores` remains {Alice=5} (because there was no entry with the key "Bob")
Add a key with the result of a specified operation as value, only if there isn't an entry yet with the same key:
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.computeIfAbsent("Alice", key -> key.length());
// `scores` remains {Alice=95}
scores.computeIfAbsent("Bob", key -> key.length());
// `scores` becomes {Alice=95, Bob=3}
// Note that the lambda expression in computeIfAbsent() only has one parameter for the key, unlike in compute() and computeIfPresent()!
Add all entries of a Map to another Map:
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores1 = new HashMap<>();
scores1.put("Alice", 95);
Map<String, Integer> scores2 = new HashMap<>();
scores2.put("Bob", 88);
scores2.put("Charlie", 90);
scores1.putAll(scores2);
// `scores1` becomes {Bob=88, Alice=95, Charlie=90}
Query value of a key
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
Integer aliceScore = scores.get("Alice"); // 95
Integer unknown = scores.get("Charlie"); // null
Provide a default value used if key doesn't have a value:
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
Integer aliceScore = scores.getOrDefault("Alice", 67); // 95
Integer unknown = scores.getOrDefault("Charlie", 67); // 67
Get number of entries
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.put("Bob", 88);
int size = scores.size(); // 2
Check if Map is empty
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores = new HashMap<>();
boolean isEmpty = scores.isEmpty(); // true
Get entries, keys, or values of Map
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Collection;
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.put("Bob", 88);
Set<String> keys = scores.keySet(); // ["Alice", "Bob"]
Collection<Integer> values = scores.values(); // [95, 88]
Set<Map.Entry<String, Integer>> entries = scores.entrySet(); // [Bob=88, Alice=95]
Check if Map contains a key or value
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
boolean hasAlice = scores.containsKey("Alice"); // true
boolean has95 = scores.containsValue(95); // true
Check if Map contains all entries of another Map
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.put("Bob", 88);
Map<String, Integer> subset = new HashMap<>();
subset.put("Alice", 95);
boolean containsSubset = scores.entrySet().containsAll(subset.entrySet()); // true
Modify value of a key
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.put("Alice", 97);
// or
scores.replace("Alice", 97);
// original value of "Alice" is overridden, `scores` becomes {Alice=97}
Modify value of a key only if it has a specific value:
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.replace("Alice", 96, 97);
// `scores` remains {Alice=95}
scores.replace("Alice", 95, 97);
// `scores` becomes {Alice=97}
Merge new value with old value based on a specified logic:
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 97);
scores.merge("Alice", 1, (oldValue, newValue) -> oldValue + newValue);
// `scores` becomes {Alice=98}
Modify all values based on a specified logic:
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.replaceAll((key, value) -> value+1);
// `scores` becomes {Alice=96}
Remove entries
Remove a single entry by key, return its value:
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.put("Bob", 88);
scores.put("Charlie", 90);
Integer removed = scores.remove("Alice"); // 95
// `scores` becomes {Bob=88, Charlie=90}
Integer notFound = scores.remove("Daniel"); // null
// `scores` remains {Bob=88, Charlie=90}
Remove entry where both key and value match:
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.put("Bob", 88);
scores.put("Charlie", 90);
boolean isItRemoved = scores.remove("Alice", 67); // false
// `scores` remains {Alice=95, Bob=88, Charlie=90}
boolean isItRemoved2 = scores.remove("Alice", 95); // true
// `scores` becomes {Bob=88, Charlie=90}
Remove all entries:
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.put("Bob", 88);
scores.put("Charlie", 90);
scores.clear();
// `scores` becomes empty
Remove all entries, the key of which is present in the provided Collection:
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.put("Bob", 88);
scores.put("Charlie", 90);
Set<String> toRemove = Set.of("Alice", "Bob");
scores.keySet().removeAll(toRemove);
// `scores` becomes {Charlie=90}
Remove all entries matching the specified condition:
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.put("Bob", 88);
scores.put("Charlie", 90);
scores.entrySet().removeIf(entry -> entry.getValue() < 90);
// `scores` becomes {Alice=95, Charlie=90}
Iterate over Map
Using forEach():
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.put("Bob", 88);
scores.put("Charlie", 90);
scores.forEach((key, value) -> System.out.println(key + ": " + value));
Iterate over entries using enhanced for loop:
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.put("Bob", 88);
scores.put("Charlie", 90);
Set<Map.Entry<String, Integer>> entries = scores.entrySet();
for (Map.Entry<String, Integer> entry : entries) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
Copy Map
Shallow copy (using constructor copy):
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
Map<String, List<Integer>> grades = new HashMap<>();
List<Integer> aliceGrades = new ArrayList<>(Arrays.asList(2, 4, 1));
grades.put("Alice", aliceGrades);
Map<String, List<Integer>> gradesCopy = new HashMap<>(grades);
List<Integer> bobGrades = new ArrayList<>(Arrays.asList(1, 5, 3));
gradesCopy.put("Bob", bobGrades);
// `grades` remains {Alice=[2, 4, 1]}
// `gradesCopy` becomes {Bob=[1, 5, 3], Alice=[2, 4, 1]}
aliceGrades.add(1);
// `grades` becomes {Alice=[2, 4, 1, 1]}
// `gradesCopy` becomes {Bob=[1, 5, 3], Alice=[2, 4, 1, 1]}
Shallow copy (using clone() method) - variable must be the same type as the stored object, can't be of superclass type!:
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
HashMap<String, List<Integer>> grades = new HashMap<>();
List<Integer> aliceGrades = new ArrayList<>(Arrays.asList(2, 4, 1));
grades.put("Alice", aliceGrades);
HashMap<String, List<Integer>> gradesCopy = (HashMap<String, List<Integer>>) grades.clone();
List<Integer> bobGrades = new ArrayList<>(Arrays.asList(1, 5, 3));
gradesCopy.put("Bob", bobGrades);
// `grades` remains {Alice=[2, 4, 1]}
// `gradesCopy` becomes {Bob=[1, 5, 3], Alice=[2, 4, 1]}
aliceGrades.add(1);
// `grades` becomes {Alice=[2, 4, 1, 1]}
// `gradesCopy` becomes {Bob=[1, 5, 3], Alice=[2, 4, 1, 1]}
Deep copy (using enhanced for loop):
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
Map<String, List<Integer>> grades = new HashMap<>();
List<Integer> aliceGrades = new ArrayList<>(Arrays.asList(2, 4, 1));
grades.put("Alice", aliceGrades);
Map<String, List<Integer>> gradesCopy = new HashMap<>();
for (Map.Entry<String, List<Integer>> entry : grades.entrySet()) {
String key = entry.getKey();
// ArrayList is only shallow copied because Integer elements are immutable
// for more details about copying a List, see the Java Lists cheatsheet
List<Integer> value = new ArrayList<>(entry.getValue());
gradesCopy.put(key, value);
}
List<Integer> bobGrades = new ArrayList<>(Arrays.asList(1, 5, 3));
gradesCopy.put("Bob", bobGrades);
// `grades` remains {Alice=[2, 4, 1]}
// `gradesCopy` becomes {Bob=[1, 5, 3], Alice=[2, 4, 1]}
aliceGrades.add(1);
// `grades` becomes {Alice=[2, 4, 1, 1]}
// `gradesCopy` remains {Bob=[1, 5, 3], Alice=[2, 4, 1]}
Deep copy (using Stream - only for Java 8 and higher):
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.stream.Collectors;
Map<String, List<Integer>> grades = new HashMap<>();
List<Integer> aliceGrades = new ArrayList<>(Arrays.asList(2, 4, 1));
grades.put("Alice", aliceGrades);
Map<String, List<Integer>> gradesCopy = grades.entrySet().stream()
.collect(Collectors.toMap(
entry -> entry.getKey(),
entry -> new ArrayList<>(entry.getValue())
));
List<Integer> bobGrades = new ArrayList<>(Arrays.asList(1, 5, 3));
gradesCopy.put("Bob", bobGrades);
// `grades` remains {Alice=[2, 4, 1]}
// `gradesCopy` becomes {Bob=[1, 5, 3], Alice=[2, 4, 1]}
aliceGrades.add(1);
// `grades` becomes {Alice=[2, 4, 1, 1]}
// `gradesCopy` remains {Bob=[1, 5, 3], Alice=[2, 4, 1]}
Unmodifiable copy:
import java.util.HashMap;
import java.util.Map;
import java.util.Collections;
Map<String, List<Integer>> grades = new HashMap<>();
List<Integer> aliceGrades = new ArrayList<>(Arrays.asList(2, 4, 1));
grades.put("Alice", aliceGrades);
Map<String, List<Integer>> gradesLocked = Collections.unmodifiableMap(grades);