Словари: Map и HashMap
Словарь (Map) хранит пары «ключ — значение»: телефон по имени, цену по названию товара, количество по слову. По ключу значение находится сразу, без перебора всех элементов.
Создание и чтение
Основная реализация — HashMap. В угловых скобках указывают два типа: ключа и значения. put() добавляет пару, get() возвращает значение по ключу:
void main() {
Map<String, Integer> ages = new HashMap<>();
ages.put("Анна", 28);
ages.put("Олег", 35);
IO.println(ages.get("Анна"));
IO.println(ages.size());
}Результат:
28
2Ключи в словаре уникальны. Повторный put() с тем же ключом заменяет старое значение.
Если ключа нет
Для отсутствующего ключа get() возвращает null. Метод getOrDefault() позволяет указать запасное значение, а containsKey() — просто проверить ключ:
void main() {
Map<String, Double> prices = new HashMap<>();
prices.put("чай", 4.5);
IO.println(prices.get("кофе"));
IO.println(prices.getOrDefault("кофе", 0.0));
IO.println(prices.containsKey("чай"));
}Результат:
null
0.0
trueИзменение и удаление
put() перезаписывает значение, remove() удаляет пару по ключу. Map.of() создаёт небольшой неизменяемый словарь:
void main() {
Map<String, Integer> stock = new HashMap<>(Map.of("яблоки", 10, "груши", 4));
stock.put("яблоки", 7);
stock.remove("груши");
IO.println(stock);
}Результат:
{яблоки=7}Подсчёт с merge()
Метод merge() удобен для счётчиков: если ключа нет, он кладёт начальное значение, а если есть — объединяет старое и новое значение функцией. Integer::sum означает «сложить два числа»:
void main() {
String text = "кот пёс кот рыба кот пёс";
Map<String, Integer> counts = new TreeMap<>();
for (String word : text.split(" ")) {
counts.merge(word, 1, Integer::sum);
}
IO.println(counts);
}Результат:
{кот=3, пёс=2, рыба=1}Запись Integer::sum — ссылка на метод; подробно они разобраны в главе об обобщениях и лямбдах.
Порядок ключей
HashMap, как и HashSet, не хранит порядок. TreeMap из примера выше держит ключи отсортированными, а LinkedHashMap помнит порядок добавления:
void main() {
Map<String, Integer> menu = new LinkedHashMap<>();
menu.put("суп", 5);
menu.put("салат", 4);
menu.put("десерт", 3);
for (Map.Entry<String, Integer> item : menu.entrySet()) {
IO.println(item.getKey() + ": " + item.getValue() + " €");
}
}Результат:
суп: 5 €
салат: 4 €
десерт: 3 €entrySet() возвращает все пары, а у каждой пары есть getKey() и getValue(). Другие способы обойти словарь — в следующем уроке.
Частая ошибка
Если значение отсутствующего ключа сразу положить в int, Java попытается превратить null в число и упадёт:
void main() {
Map<String, Integer> stock = Map.of("чай", 3);
int coffee = stock.get("кофе");
}Результат:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because the return value of "java.util.Map.get(Object)" is nullИспользуйте getOrDefault("кофе", 0) или проверьте ключ через containsKey().