1. Множина пар: ключ–значення
>
У Java є ще одна цікава колекція (в широкому сенсі) — це колекція Map. Точного перекладу її назви немає: найчастіше її називають «карта», «словник» або просто «мапа» — саме цей термін ми й використовуватимемо надалі.
Ця колекція схожа на колекцію Set, але зберігає не множину елементів, а множину «пар елементів». Кожна пара елементів Map — це «ключ» і «значення».
Припустімо, ви хочете зберігати в програмі імена працівників компанії та їхні зарплати або імена своїх колег та їхній вік. Тоді вам знадобиться така таблиця:
| Ім'я | Вік |
|---|---|
| Сергій | 21 |
| Микола | 22 |
| Іван Петрович | 48 |
| Ганнуся | ? |
Тут у кожному рядку зберігається пара значень. Ім'я будемо називати ключем пари, а вік — значенням пари.
Увесь набір таких пар і буде називатися мапою — Map.
Ключем пари може бути що завгодно, але у деяких типів мап ключ не може мати значення null. Ключі мають бути унікальними: одна мапа не може містити два однакових ключі.
2. Клас HashMap
Клас HashMap — це найпопулярніша колекція з усіх мап (Map). З одного боку, він дуже схожий на HashSet і має всі його методи, а з іншого — на список (ArrayList), якби індексами списку могли бути не числа, а слова.
Створити об'єкт типу HashMap можна за допомогою такої команди:
HashMap<TКлюч, TЗначення> ім'я = new HashMap<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 і HashMap
HashMap дуже нагадує ArrayList, в якому індексами є не цифри, а слова (або інший тип ключів).
А якщо використовувати в HashMap ключ типу Integer, ця колекція стане ще більше схожою на ArrayList. Порівняйте:
| Код з ArrayList<String> | Код із HashMap<Integer, String> |
|---|---|
|
|
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ