CodeGym /Kursy /JAVA 25 SELF /Map: HashMap i TreeMap, klucze i wartości

Map: HashMap i TreeMap, klucze i wartości

JAVA 25 SELF
Poziom 26 , Lekcja 2
Dostępny

1. Wprowadzenie

W prawdziwym życiu często spotykamy się z sytuacjami, gdy każdemu unikalnemu „kluczowi” trzeba przypisać jakąś „wartość”. Książka telefoniczna przechowuje numer telefonu i imię osoby, słownik wiąże słowo z jego tłumaczeniem, a w tabeli ocen każdy student ma swoje imię i odpowiedni wynik.

W Javie do takich zadań służy interfejs Map. To kolekcja, która przechowuje pary „klucz — wartość” (key-value pair).

Najważniejsze właściwości Map:

  • Każdy klucz jest unikalny (duplikaty nie są dozwolone).
  • Jednemu kluczowi może odpowiadać tylko jedna wartość.
  • Wartości mogą się powtarzać.

Wyobraźmy sobie analogię. Jeśli lista (List) to jak kolejka w stołówce (każdy stoi na swojej pozycji, można odwołać się po numerze), to mapa (Map) to jak szafka z przegródkami: każda przegródka ma numer (klucz), a w środku leży coś własnego (wartość).

Interfejs Map: podstawowe operacje

Interfejs Map deklaruje podstawowe metody do pracy z parami klucz–wartość:

Metoda Opis
put(K key, V value)
Dodać/zastąpić wartość dla klucza
get(K key)
Pobrać wartość dla klucza
remove(K key)
Usunąć parę według klucza
containsKey(K key)
Sprawdzić, czy istnieje taki klucz
containsValue(V value)
Sprawdzić, czy istnieje taka wartość
size()
Liczba par w mapie
isEmpty()
Sprawdzić, czy Map jest pusta
clear()
Usunąć wszystkie pary

Typy K i V — to parametry generyczne: K (Key) — typ klucza, V (Value) — typ wartości.

3. Klasa HashMap: szybki dostęp po kluczu

Co to jest HashMap?

HashMap to najpopularniejsza implementacja interfejsu Map. Zapewnia szybki dostęp do wartości po kluczu.

Ważne: HashMap nie gwarantuje porządku przechowywania elementów! Jeśli dodasz klucze w określonej kolejności, przy iteracji mogą występować w innej.

Jak utworzyć HashMap?

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

public class Example {
    public static void main(String[] args) {
        // Tworzymy mapę: klucz — String, wartość — Integer
        Map<String, Integer> ages = new HashMap<>();

        // Dodajemy elementy
        ages.put("John", 25);
        ages.put("Peter", 30);
        ages.put("Mary", 22);

        // Pobieramy wartość dla klucza
        int vasyaAge = ages.get("John");
        System.out.println("Wiek John: " + vasyaAge); // 25

        // Sprawdzamy obecność klucza
        if (ages.containsKey("Mary")) {
            System.out.println("Mary jest na liście!");
        }

        // Usuwamy element
        ages.remove("Peter");

        // Iterujemy po wszystkich parach klucz-wartość
        for (String name : ages.keySet()) {
            System.out.println(name + ": " + ages.get(name));
        }
    }
}

Wynik:

Wiek John: 25
Mary jest na liście!
John: 25
Mary: 22

Cechy HashMap

Najważniejsze, o czym należy pamiętać: klucze w HashMap zawsze są unikalne. Jeśli wstawisz nowy element z już istniejącym kluczem, stara wartość zostanie zastąpiona nową.

Wartości mogą się powtarzać: kilka różnych kluczy może wskazywać tę samą wartość.

Jeszcze jedna ważna kwestia — porządek elementów. HashMap nie dba o kolejność dodania. Przy wypisywaniu wpisy mogą być przemieszane — to normalne zachowanie.

4. Klasa TreeMap: sortowanie według klucza

W przeciwieństwie do HashMap, klasa TreeMap przechowuje elementy w porządku posortowanym według klucza.

Kiedy używać TreeMap?

Gdy ważne jest, aby elementy były ułożone rosnąco (lub malejąco) według kluczy. Na przykład, jeśli chcesz wypisać książkę telefoniczną alfabetycznie.

Przykład:

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("John", "+1-900-123-45-67");
        phoneBook.put("Mary", "+1-900-555-55-55");
        phoneBook.put("Peter", "+1-900-222-33-44");

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

Wynik:

Mary: +1-900-555-55-55
Peter: +1-900-222-33-44
John: +1-900-123-45-67

Zwróć uwagę: klucze są posortowane alfabetycznie.

5. Podstawowe operacje na Map

Dodawanie i zastępowanie elementów
Map<String, Integer> scores = new HashMap<>();
scores.put("Anna", 90);
scores.put("Ivan", 85);
scores.put("Anna", 95); // Nadpisze wartość dla "Anna"
Pobieranie wartości
Integer annaScore = scores.get("Anna"); // 95
Integer unknown = scores.get("John");   // null, jeśli takiego klucza nie ma
Sprawdzanie obecności klucza lub wartości
scores.containsKey("Ivan");    // true
scores.containsValue(85);      // true
Usuwanie pary według klucza
scores.remove("Ivan");
Rozmiar mapy i czyszczenie
int size = scores.size();
scores.clear(); // Usuwa wszystkie elementy

5. Iteracja po elementach Map

Map to nie lista — nie ma tu indeksów. Można jednak iterować:

Po kluczach:

for (String key : scores.keySet()) {
    System.out.println("Klucz: " + key + ", Wartość: " + scores.get(key));
}

Po wartościach:

for (Integer value : scores.values()) {
    System.out.println("Wartość: " + value);
}

Po parach klucz–wartość (najlepszy sposób):

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

Kiedy używać HashMap, a kiedy — TreeMap?

HashMap to uniwersalny, domyślny wybór. Jeśli kolejność kluczy nie ma znaczenia, a najważniejsza jest szybkość operacji, prawie zawsze wybiera się właśnie ją.

TreeMap przydaje się, gdy potrzebny jest porządek. Automatycznie przechowuje klucze posortowane i pozwala szybko znaleźć minimalny/maksymalny klucz lub pracować z zakresami.

Podsumowując: w 90 % przypadków wybieramy HashMap. Gdy dane mają być od razu „w porządku”, używamy TreeMap.

6. Przykłady użycia Map

Przykład 1: Książka telefoniczna

Map<String, String> phoneBook = new HashMap<>();
phoneBook.put("Kate", "+1-999-111-22-33");
phoneBook.put("Oliver", "+1-999-222-33-44");
phoneBook.put("Kate", "+1-999-555-66-77"); // Stary numer Katyi zostanie zastąpiony nowym

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

Wynik:

Oliver: +1-999-222-33-44
Kate: +1-999-555-66-77

Przykład 2: Zliczanie wystąpień słów

Załóżmy, że mamy listę słów i chcemy sprawdzić, ile razy każde słowo występuje:

import java.util.*;

public class WordCount {
    public static void main(String[] args) {
        List<String> words = Arrays.asList("jabłko", "banan", "jabłko", "gruszka", "banan", "jabłko");
        Map<String, Integer> counts = new HashMap<>();

        for (String word : words) {
            int oldCount = counts.getOrDefault(word, 0); // jeśli klucza nie ma — 0
            counts.put(word, oldCount + 1);
        }

        System.out.println(counts); // {gruszka=1, jabłko=3, banan=2}
    }
}

7. Typowe błędy podczas pracy z Map

Błąd nr 1: Mylenie kluczy i wartości. Początkujący często próbują pobrać wartość po indeksie, jak na liście, albo zapominają, że klucze muszą być unikalne. W Map nie ma indeksów — są tylko klucze.

Błąd nr 2: Używanie kluczy i wartości null. W HashMap dopuszczalny jest klucz null, ale w TreeMap — nie (pojawi się NullPointerException). Wartości mogą być null w obu implementacjach, lecz rzadko jest to użyteczne.

Błąd nr 3: Oczekiwanie porządku elementów w HashMap. HashMap nie gwarantuje żadnej kolejności. Jeśli potrzebny jest porządek — użyj LinkedHashMap (zachowuje kolejność dodawania) lub TreeMap (sortuje według klucza).

Błąd nr 4: Modyfikacja Map podczas iteracji. Jeśli w pętli iterujesz po Map i jednocześnie dodajesz/usuwasz elementy — może wystąpić ConcurrentModificationException. Do takich zadań użyj iteratora z metodą remove() lub specjalnych kolekcji.

Błąd nr 5: Porównywanie kluczy i wartości za pomocą == zamiast equals. Map używa metody equals do porównywania kluczy (i wartości). Jeśli tworzysz własne klasy‑klucze, koniecznie nadpisz equals i hashCode.

1
Zadanie
JAVA 25 SELF, poziom 26, lekcja 2
Niedostępne
Inteligentny planer zadań: dni tygodnia 🗓️
Inteligentny planer zadań: dni tygodnia 🗓️
1
Zadanie
JAVA 25 SELF, poziom 26, lekcja 2
Niedostępne
Inwentaryzacja owoców w magazynie w kolejności alfabetycznej 🍏🍌🍐
Inwentaryzacja owoców w magazynie w kolejności alfabetycznej 🍏🍌🍐
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION