JavaRush /Курси /JAVA 25 SELF /Map: HashMap і TreeMap, ключі та значення

Map: HashMap і TreeMap, ключі та значення

JAVA 25 SELF
Рівень 26 , Лекція 2
Відкрита

1. Вступ

У реальному житті ми часто стикаємося із ситуаціями, коли кожному унікальному «ключу» потрібно зіставити певне «значення». Телефонна книга зберігає номер телефону та імʼя людини, словник пов’язує слово з його перекладом, а в таблиці оцінок у кожного студента є власне імʼя та відповідний бал.

У Java для таких завдань є інтерфейс Map. Це колекція, що зберігає пари «ключ — значення» (key-value pair).

Головні властивості Map:

  • Кожен ключ унікальний (дублікати не допускаються).
  • Одному ключу може відповідати лише одне значення.
  • Значення можуть повторюватися.

Уявімо аналогію. Якщо список (List) — це як черга в їдальні (кожен стоїть на своїй позиції, можна звернутися за номером), то відображення (Map) — це ніби шафка з комірками: кожна комірка має номер (ключ) і в ній лежить щось своє (значення).

Інтерфейс Map: базові операції

Інтерфейс Map оголошує основні методи для роботи з парами ключ-значення:

Метод Опис
put(K key, V value)
Додати або замінити значення за ключем
get(K key)
Отримати значення за ключем
remove(K key)
Видалити пару за ключем
containsKey(K key)
Перевірити, чи є такий ключ
containsValue(V value)
Перевірити, чи є таке значення
size()
Кількість пар у відображенні
isEmpty()
Перевірити, чи порожня мапа
clear()
Видалити всі пари

Типи K і V — це параметри типу (generics): K (Key) — тип ключа, V (Value) — тип значення.

3. Клас HashMap: швидкий доступ за ключем

Що таке HashMap?

HashMap — найпопулярніша реалізація інтерфейсу Map. Вона забезпечує швидкий доступ до значень за ключем.

Важливо: HashMap не гарантує порядок зберігання елементів! Якщо ви додали ключі у певному порядку, під час перебирання вони можуть іти в іншому.

Як створити HashMap?

import java.util.HashMap;
import java.util.Map;

public class Example {
    public static void main(String[] args) {
        // Створюємо мапу: ключ — String, значення — Integer
        Map<String, Integer> ages = new HashMap<>();

        // Додаємо елементи
        ages.put("Василь", 25);
        ages.put("Петро", 30);
        ages.put("Марія", 22);

        // Отримуємо значення за ключем
        int vasyaAge = ages.get("Василь");
        System.out.println("Вік Василя: " + vasyaAge); // 25

        // Перевіряємо наявність ключа
        if (ages.containsKey("Марія")) {
            System.out.println("Марія є у списку!");
        }

        // Видаляємо елемент
        ages.remove("Петро");

        // Перебираємо всі пари ключ-значення
        for (String name : ages.keySet()) {
            System.out.println(name + ": " + ages.get(name));
        }
    }
}

Виведення:

Вік Василя: 25
Марія є у списку!
Василь: 25
Марія: 22

Особливості HashMap

Головне, що варто пам’ятати: ключі в HashMap завжди унікальні. Якщо ви додасте новий елемент із уже наявним ключем, старе значення буде замінено новим.

Значення можуть повторюватися: кілька різних ключів можуть вказувати на одне й те саме значення.

І ще важливий момент — порядок елементів. HashMap не дбає про порядок додавання. Під час виведення записи можуть бути перемішані — це нормальна поведінка.

4. Клас TreeMap: сортування за ключем

На відміну від HashMap, клас TreeMap зберігає елементи у відсортованому порядку за ключем.

Коли використовувати TreeMap?

Коли важливо, щоб елементи йшли у зростаючому (або спадному) порядку ключів. Наприклад, якщо ви хочете вивести телефонну книгу за абеткою.

Приклад:

import java.util.Map;
import java.util.TreeMap;

public class TreeMapExample {
    public static void main(String[] args) {
        Map<String, String> phoneBook = new TreeMap<>();

        phoneBook.put("Василь", "+1-900-123-45-67");
        phoneBook.put("Марія", "+1-900-555-55-55");
        phoneBook.put("Петро", "+1-900-222-33-44");

        for (String name : phoneBook.keySet()) {
            System.out.println(name + ": " + phoneBook.get(name));
        }
    }
}

Виведення:

Марія: +1-900-555-55-55
Петро: +1-900-222-33-44
Василь: +1-900-123-45-67

Зверніть увагу: ключі відсортовані за абеткою.

5. Основні операції з Map

Додавання та заміна елементів
Map<String, Integer> scores = new HashMap<>();
scores.put("Анна", 90);
scores.put("Іван", 85);
scores.put("Анна", 95); // Перезапише значення для "Анна"
Отримання значення
Integer annaScore = scores.get("Анна"); // 95
Integer unknown = scores.get("Василь"); // null, якщо такого ключа немає
Перевірка наявності ключа або значення
scores.containsKey("Іван");    // true
scores.containsValue(85);      // true
Видалення пари за ключем
scores.remove("Іван");
Розмір мапи та очищення
int size = scores.size();
scores.clear(); // Видаляє всі елементи

5. Перебирання елементів Map

Map — це не список, індексів тут немає. Проте можна ітеруватися:

За ключами:

for (String key : scores.keySet()) {
    System.out.println("Ключ: " + key + ", Значення: " + scores.get(key));
}

За значеннями:

for (Integer value : scores.values()) {
    System.out.println("Значення: " + value);
}

За парами ключ — значення (найкращий спосіб):

for (Map.Entry<String, Integer> entry : scores.entrySet()) {
    String key = entry.getKey();
    Integer value = entry.getValue();
    System.out.println(key + " => " + value);
}

Коли використовувати HashMap, а коли — TreeMap?

HashMap — універсальний варіант «за замовчуванням». Якщо порядок ключів неважливий і головне — швидкість операцій, майже завжди беруть саме його.

TreeMap стане у пригоді, якщо потрібен порядок. Він автоматично зберігає ключі відсортованими та дозволяє швидко знаходити мінімальний і максимальний ключ або працювати з діапазонами.

Підсумок: у 90 % випадків беремо HashMap. Коли дані мають бути одразу «в порядку», використовуємо TreeMap.

6. Приклади використання Map

Приклад 1: Телефонна книга

Map<String, String> phoneBook = new HashMap<>();
phoneBook.put("Катя", "+1-999-111-22-33");
phoneBook.put("Олег", "+1-999-222-33-44");
phoneBook.put("Катя", "+1-999-555-66-77"); // Старий номер Каті буде замінено новим

for (Map.Entry<String, String> entry : phoneBook.entrySet()) {
    System.out.println(entry.getKey() + ": " + entry.getValue());
}

Виведення:

Олег: +1-999-222-33-44
Катя: +1-999-555-66-77

Приклад 2: Підрахунок кількості слів

Припустімо, у нас є список слів, і ми хочемо дізнатися, скільки разів кожне слово трапляється:

import java.util.*;

public class WordCount {
    public static void main(String[] args) {
        List<String> words = Arrays.asList("яблуко", "банан", "яблуко", "груша", "банан", "яблуко");
        Map<String, Integer> counts = new HashMap<>();

        for (String word : words) {
            int oldCount = counts.getOrDefault(word, 0); // якщо ключа немає — 0
            counts.put(word, oldCount + 1);
        }

        System.out.println(counts); // {груша=1, яблуко=3, банан=2}
    }
}

7. Типові помилки під час роботи з Map

Помилка № 1: Плутанина між ключами та значеннями. Новачки часто намагаються отримати значення за індексом, як у списку, або забувають, що ключі мають бути унікальними. У Map немає індексів — лише ключі.

Помилка № 2: Використання ключів і значень null. У HashMap дозволений ключ null, але в TreeMap — ні (буде NullPointerException). Значення можуть бути null в обох реалізаціях, але це рідко буває корисним.

Помилка № 3: Очікування порядку елементів у HashMap. HashMap не гарантує жодного порядку. Якщо потрібен порядок — використовуйте LinkedHashMap (зберігає порядок додавання) або TreeMap (сортує за ключем).

Помилка № 4: Модифікація Map під час ітерації. Якщо ви в циклі ітеруєте Map і водночас додаєте або видаляєте елементи — може виникнути ConcurrentModificationException. Для таких завдань використовуйте ітератор із методом remove() або спеціальні колекції.

Помилка № 5: Порівняння ключів і значень за == замість equals. Map використовує метод equals для порівняння ключів (і значень). Якщо ви створюєте власні класи-ключі, обов’язково перевизначайте equals і hashCode.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ