JavaRush /Курси /Java Syntax Zero /Знайомство з колекцією HashMap

Знайомство з колекцією HashMap

Java Syntax Zero
Рівень 14 , Лекція 4
Відкрита

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 є такі методи:

Метод Опис
void put(ТКлюч key, ТЗначення value)
Додає в колекцію пару (key, value)
ТЗначення get(ТКлюч key)
Повертає значення за ключем.
boolean containsKey(ТКлюч key)
Перевіряє наявність ключа в колекції
boolean containsValue(ТЗначення value)
Перевіряє наявність значення в колекції
ТЗначення remove(ТКлюч key)
Видаляє елемент з колекції
void clear()
Очищає колекцію: видаляє всі елементи
int size()
Повертає кількість пар елементів у колекції
Set<ТКлюч> keySet()
Повертає множину ключів колекції
Collection<ТЗначення> values()
Повертає множину елементів колекції
Set<Map.Entry<TКлюч, TЗначення>> entrySet()
Повертає всі значення колекції у вигляді множини (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(), а як пройтися по множині ви вже знаєте:

Код Опис
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("Сергій", 21);
map.put("Микола", 22);
map.put("Іван Петрович", 48);
map.put("Анюта", null);

for (String key: map.keySet())
{
   Integer value = map.get(key);
   System.out.println(key + " --> " + value);
}






Цикл по всіх ключах map

Отримуємо значення за ключем

Метод keySet() повертає множину ключів. Можна використовувати цю множину двома способами:

Компактний запис Довгий запис
for (String key: map.keySet())
{
   Integer value = map.get(key);
   System.out.println(key + " --> " + value);
}
Set<String> keys = map.keySet();

for (String key: keys)
{
   Integer value = map.get(key);
   System.out.println(key + " --> " + value);
}


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>
ArrayList<String> list = new ArrayList<String>();

list.add("Привіт");
list.add("Hello");

String s = list.get(0);
list.set(0, s + "!");

for (String item: list)
{
   System.out.println(item);
}
HashMap<Integer, String> map = new HashMap<Integer, String>();

map.put(0, "Привіт");
map.put(1, "Hello");

String s = map.get(0);
map.put(0, s + "!");

for (String item: map.values())
{
   System.out.println(item);
}

Коментарі (16)
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ
Soros Рівень 25
27 серпня 2025
Методу void put(ТКлюч key, ТЗначення value) у класі HashMap немає! Існує метод V put(ТКлюч key, ТЗначення value) - тобто цей метод повертає або null в тому випадку, коли такого ключа ще не додавалось, або ТЗначення value, якщо така сама пара вже існує в HashMap об'єкті
Михайло Рівень 117
8 січня 2025
3 задача тупо копіпаста з лекції)
Кирило Рівень 43
19 липня 2024
Шось я завис на успішності студентів-2
Ivan Maksymovych Рівень 1 Expert
5 вересня 2023
в задачке Успішність студента 3 можно же решить все намного проще и легче, благодаря пройденным темам)

for (String names: grades.keySet()
             ) {
            System.out.println(names +" : "+grades.get(names) );

        }
Все выводится как нужно, но валидатор не пустит все равно)))
10 жовтня 2023
а можно и так:


for (var entry :
                grades.entrySet()) {
            System.out.println(entry.getKey() + " : " + entry.getValue());
3 строки кода, море удовольствия!
2 липня 2023
А як створити об'єкт HashMap і одразу при ініціалізації додати до нього елементи(пари) без метода put?
Ihor Prokudin Рівень 51
22 березня 2023
Годину сидів і намагався зрозуміти про Set<Entry<>>, сходив по каву і до мене дійшло :/
Roma Chernesh Рівень 16
8 лютого 2023
Ото може в мене одного так, але щось тема із колекціями дуже важкой йде. Знаю, що початківцям зазвичай не вдається зрозуміти роботу подвійних (чи потрійних) масивів. Але якось ту тему вдалося пережувати і втянутися. А тут прям повна каша:(
[V.I.R.U.S.] Рівень 24 Expert
21 лютого 2023
Мужик. ти маєш зрозуміти що все геніальне просте. Не пошкодуй свій час і пройдись назад по темам масивів. Включай в Ютубі різних блогерів+ прочитай 2-3 статті на цю тему від різних авторів. І все стане на свої місця.
Roma Chernesh Рівень 16
22 лютого 2023
Та згоден! Ото який код не побачу по джуві - усюди ці колекції. Тому, каша-не каша, а розуміти треба!
Anonymous #696530 Рівень 19
28 вересня 2022
По класу Entry інтуїтивно зрозуміло, що воно все круто і зручно, але самостійно такими речами поки важко оперувати... особливо зі скороченнями.. По Задачі "Успішність студентів-3" скопіював код з лекції і адаптував за 2 хв, таке вже нормально виходить, не знаю добре це чи погано... ))
Andriy Рівень 20
10 серпня 2022
Задачу про перетворення ArrayList в HashMap можна вирішити не замінюючи ArrayList на HashMap, а циклом витягнути з нього індекси і значення, яким потім наповнити HashMap
Pavlo Kezin Рівень 23
12 вересня 2023
теж так робив, але спочатку зробив як у відповіді, але чомусь не пройшло. подумав це було обов"язково.
Lipovskyi Volodymyr Рівень 36
7 червня 2022
Задачка Успішність студентів 2. Не виконано всі вимоги, тому що використовував print замість println))) 25 спроб)))
Andriy Рівень 16
31 жовтня 2022
Не знаю чи поміняли завдяки тобі, але зараз про це вказано: • Метод printStudents має виводити імена та прізвища всіх студентів із колекції grades (кожну пару з нового рядка).