Maps: Map and HashMap
A map (Map) stores "key — value" pairs: a phone number by name, a price by product title, a count by word. A value is found by its key right away, without going through all the elements.
Creating and reading
The main implementation is HashMap. Two types go in the angle brackets: the key's and the value's. put() adds a pair, get() returns the value for a key:
void main() {
Map<String, Integer> ages = new HashMap<>();
ages.put("Anna", 28);
ages.put("Oleg", 35);
IO.println(ages.get("Anna"));
IO.println(ages.size());
}Output:
28
2Keys in a map are unique. Calling put() again with the same key replaces the old value.
When the key is missing
For a missing key get() returns null. The getOrDefault() method lets you give a fallback value, and containsKey() simply checks the key:
void main() {
Map<String, Double> prices = new HashMap<>();
prices.put("tea", 4.5);
IO.println(prices.get("coffee"));
IO.println(prices.getOrDefault("coffee", 0.0));
IO.println(prices.containsKey("tea"));
}Output:
null
0.0
trueChanging and removing
put() overwrites a value, remove() deletes a pair by key. Map.of() creates a small unmodifiable map:
void main() {
Map<String, Integer> stock = new HashMap<>(Map.of("apples", 10, "pears", 4));
stock.put("apples", 7);
stock.remove("pears");
IO.println(stock);
}Output:
{apples=7}Counting with merge()
The merge() method is handy for counters: if the key is missing, it puts the initial value, and if it is there, it combines the old and new values with a function. Integer::sum means "add two numbers":
void main() {
String text = "cat dog cat fish cat dog";
Map<String, Integer> counts = new TreeMap<>();
for (String word : text.split(" ")) {
counts.merge(word, 1, Integer::sum);
}
IO.println(counts);
}Output:
{cat=3, dog=2, fish=1}The notation Integer::sum is a method reference; they are covered in detail in the chapter on generics and lambdas.
Key order
HashMap, like HashSet, does not keep order. The TreeMap from the example above keeps keys sorted, and LinkedHashMap remembers the insertion order:
void main() {
Map<String, Integer> menu = new LinkedHashMap<>();
menu.put("soup", 5);
menu.put("salad", 4);
menu.put("dessert", 3);
for (Map.Entry<String, Integer> item : menu.entrySet()) {
IO.println(item.getKey() + ": " + item.getValue() + " €");
}
}Output:
soup: 5 €
salad: 4 €
dessert: 3 €entrySet() returns all pairs, and each pair has getKey() and getValue(). Other ways to go through a map are in the next lesson.
Common mistake
If you put the value of a missing key straight into an int, Java tries to turn null into a number and crashes:
void main() {
Map<String, Integer> stock = Map.of("tea", 3);
int coffee = stock.get("coffee");
}Output:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because the return value of "java.util.Map.get(Object)" is nullUse getOrDefault("coffee", 0) or check the key with containsKey().