1. Множество пар: ключ-значение.

В Java есть еще одна интересная коллекция (в широком смысле) — это коллекция Map. Точного перевода ее названия на русский нет: чаще всего ее называют «карта», «словарь» или просто «мапа».
Эта коллекция похожа на коллекцию Set, только хранит не множество элементов, а множество «пар элементов». Каждая пара элементов Map состоит из двух: «ключ» и «значение».
Допустим, вы хотите хранить в программе имена сотрудников компании, их зарплаты или имена ваших коллег и их возраст. Тогда вам бы понадобилась таблица типа такой:
| Имя | Возраст |
|---|---|
| Сергей | 21 |
| Николай | 22 |
| Иван Петрович | 48 |
| Анюта | ? |
В каждой строке тут хранится пара величин. Имя мы будем называть ключом пары, а возраст — значением пары.
Весь набор таких пар и будет называться картой — Map.
Ключом пары может быть что угодно, но у некоторых типов карт ключ не может быть null. Ключи должны быть уникальные: одна карта не может содержать два одинаковых ключа.
2. Класс HashMap
Класс HashMap является самой популярной коллекцией из всех карт (Map). С одной стороны, он очень похож на HashSet и имеет все его методы, а с другой — на список (ArrayList), если бы индексами у списка могли быть не числа, а слова.
Создать объект типа HashMap можно с помощью команды вида:
HashMap<TКлюч, TЗначение> имя = new HashMap<TКлюч, TЗначение>();
Где TКлюч — это тип ключей из пары элементов, TЗначение — тип значений в паре элементов, которые будут храниться в коллекции HashMap.
У класса HashMap есть такие методы:
| Метод | Описание |
|---|---|
|
Добавляет в коллекцию пару (key, value) |
|
Возвращает значение по ключу. |
|
Проверяет наличие ключа в коллекции |
|
Проверяет наличие значения в коллекции |
|
Удаляет элемент из коллекции |
|
Очищает коллекцию: удаляет все элементы |
|
Возвращает количество пар элементов в коллекции |
|
Возвращает множество ключей коллекции |
|
Возвращает множество элементов коллекции |
|
Возвращает все значения коллекции в виде множества (Set) пар (Map.Entry). |
Добавление элементов в HashMap
Элементы добавляются в карту сразу парами: для этого используется метод put(). Первым в него передается ключ, вторым — значение.
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("Серега", 21);
map.put("Николай", 22);
map.put("Иван Петрович", 48);
map.put("Анюта", null);
Если при добавлении элемента выяснится, что элемент с таким ключом уже есть, старое значение ключа заменится на новое.
Такое поведение делает HashMap похожим на массив или список, если бы у них в качестве индексов выступали слова (String), а не числа.
В качестве Типа-Ключа и Типа-Значения могут выступать практически любые типы. Есть небольшие дополнительные требования к Типу-Ключу, но о них вы узнаете при детальном изучении коллекций в квесте Java Collections.
3. Подмножества HashMap: множество ключей
Допустим мы хотим просто вывести все элементы HashMap на экран, как нам это сделать? Для этого нужно понять, как пройтись по всем элементам HashMap. Это можно сделать разными способами.
Самый простой способ – использовать цикл по ключам
У элементов класса HashMap нет порядкового номера, поэтому цикл со счетчиком тут не подойдет. Зато мы можем получить множество ключей с помощью метода keySet(), а как пройтись по множеству вы уже знаете:
| Код | Описание |
|---|---|
|
Цикл по всем ключам mapПолучаем значение по ключу |
Метод keySet() возвращает множество ключей. Можно использовать это множество двумя способами:
| Компактная запись | Длинная запись |
|---|---|
|
|
4. Использование цикла по парам
Есть и более сложный способ: можно преобразовать Map в множество пар элементов, а потом использовать цикл по элементам множества, как мы уже раньше учили.
В коллекции HashMap есть вспомогательный класс для хранения пары элементов. Выглядит он примерно так:
class Entry<KeyType, ValueType>
{
private KeyType key;
private ValueType value;
public KeyType getKey()
{
return this.key;
}
public ValueType getValue()
{
return this.value;
}
}
Результат вызова метода entrySet() у объекта типа HashMap<ТКлюч, ТЗначение> будет иметь тип Set<Entry<ТКлюч, ТЗначение>>:
Set<Entry<Ключ, Значение>> имя = map.entrySet();
Тут мы видим сложный тип Set с параметром-значением, а в качестве параметра-значение выступает еще один сложный тип (Entry), так еще и с двумя параметрами.
Новичку очень легко в этом запутаться. Хотя, если разберетесь, сможете писать код вида:
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("Серега", 21);
map.put("Николай", 22);
map.put("Иван Петрович", 48);
map.put("Анюта", null);
Set<Map.Entry<String, Integer>> entries = map.entrySet();
for(Map.Entry<String, Integer> pair: entries)
{
String key = pair.getKey();
Integer value = pair.getValue();
System.out.println(key + " --> " + value);
}
Хотя этот код можно и немножко упростить:
Во-первых, можно не создавать отдельную переменную для entries, а сразу вызвать метод entrySet() внутри цикла for:
for(Map.Entry<String, Integer> pair: map.entrySet())
{
String key = pair.getKey();
Integer value = pair.getValue();
System.out.println(key + " --> " + value);
}
Во-вторых, можно воспользоваться недавно появившимся оператором var для автоматического выведения типа пары элементов:
for(var pair: map.entrySet())
{
String key = pair.getKey();
Integer value = pair.getValue();
System.out.println(key + " --> " + value);
}
Уже неплохо, да?
5. Сравнение ArrayList vs HashMap
HashMap сильно напоминает ArrayList, у которого в качестве индексов используются не цифры, а слова (или другой тип ключей).
А если в качестве ключа в HashMap использовать Integer, он становится еще более похожим на ArrayList. Сравните:
| Код с ArrayList<String> | Код с HashMap<Integer, String> |
|---|---|
|
|
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ