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> |
|---|---|
|
|
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ