1. Wprowadzenie
Wiemy już, że ArrayList to „nieskończona tablica”, która rośnie sama. Ma jednak jedno ograniczenie: dostęp do elementów odbywa się po numerze (indeksie). Jeśli mamy listę z tysiącem osób i chcemy znaleźć numer Alicji, musimy albo znać jej indeks, albo przeglądać wszystkich po kolei.
W życiu często szukamy danych po unikalnym kryterium:
- po imieniu szukamy numeru telefonu,
- po numerze paszportu szukamy właściciela,
- po loginie znajdujemy hasło,
- po id szukamy obiektu w bazie.
Do tego potrzebna jest struktura, która potrafi: „otrzymuję klucz → natychmiast znajduję wartość”. W Javie zajmuje się tym HashMap<K,V>.
Analogia:
Wyobraź sobie zwykły papierowy słownik. Szukasz tłumaczenia słowa „house”. Nie musisz przewracać wszystkich stron po kolei. Od razu idziesz do litery „H” i znajdujesz potrzebne słowo. Tak działa HashMap: po kluczu (słowo) natychmiast otrzymujemy wartość (tłumaczenie).
Tworzenie słownika
Aby utworzyć słownik, trzeba wskazać, jakie typy będą kluczami i wartościami.
import java.util.HashMap;
HashMap<String, String> phonebook = new HashMap<String, String>();
Tutaj:
- String (pierwszy typ) — to typ klucza (imię osoby).
- String (drugi typ) — to typ wartości (numer telefonu).
Teraz phonebook jest jak prawdziwa książka telefoniczna.
Inne przykłady:
HashMap<String, Integer> grades = new HashMap<String, Integer>(); // imię → ocena
HashMap<Integer, String> users = new HashMap<Integer, String>(); // id → imię
HashMap<String, Boolean> flags = new HashMap<String, Boolean>(); // klucz → wartość logiczna
W przeciwieństwie do ArrayList, słownik nie ma metody add(), za to ma własne, nie mniej interesujące.
2. Metoda put(key, value) — dodać parę
Najważniejsza różnica HashMap w porównaniu z tablicami i listami polega na tym, że przechowuje nie tylko zbiór wartości, ale pary klucz–wartość. To czyni go podobnym do prawdziwego słownika: każde słowo ma tłumaczenie, każde imię — telefon, każdy login — hasło.
Przykład:
phonebook.put("Alicja", "+380501112233");
phonebook.put("Bob", "+380671234567");
Teraz w naszej książce telefonicznej:
- klucz "Alicja" jest powiązany z wartością "+10501112233",
- klucz "Bob" jest powiązany z wartością "+10671234567".
To znaczy, że aby otrzymać wartość (telefon), wystarczy znać klucz (imię).
Ważne: klucze są unikalne. Jeśli spróbujemy dodać nową wartość pod już istniejącym kluczem, stara wartość zostanie nadpisana.
phonebook.put("Alicja", "+10999999999");
Teraz u Alicji został tylko nowy numer: stary numer został utracony.
Wniosek: put to metoda do dodawania lub aktualizowania wpisów. Jeśli klucz jest nowy — wpis jest tworzony. Jeśli klucz już istnieje — wpis jest aktualizowany.
3. Metoda get(key) — pobrać wartość
Aby znaleźć wartość, trzeba znać klucz. To główna zaleta HashMap: wyszukiwanie po kluczu działa bardzo szybko, niemal natychmiast, niezależnie od tego, czy mamy tysiąc wpisów, czy milion.
Przykład:
System.out.println(phonebook.get("Alicja"));
Wynik:
+10501112233
Jeśli takiego klucza nie ma, get zwróci null:
System.out.println(phonebook.get("Charlie")); // null
To znaczy: „klucza ‚Charlie’ w słowniku nie ma”.
4. Metoda containsKey(key) — sprawdzić obecność
Aby nie natrafić na null, warto najpierw sprawdzić, czy klucz istnieje w słowniku.
Przykład:
System.out.println(phonebook.containsKey("Charlie"));
Wynik:
false
Dzięki temu możemy z góry zdecydować:
- jeśli klucza nie ma — tworzymy nowy wpis,
- jeśli klucz jest — aktualizujemy go.
Częsta praktyka:
if (phonebook.containsKey("Alicja"))
{
System.out.println("Alicja ma już numer!");
}
else
{
phonebook.put("Alicja", "+10111111111");
}
5. Metoda remove(key) — usunąć wpis
Usuwanie działa równie prosto: trzeba znać tylko klucz.
phonebook.remove("Bob");
System.out.println(phonebook.get("Bob"));
Wynik:
null
Teraz wpis z kluczem "Bob" już nie istnieje w słowniku.
6. Iteracja po wszystkich parach
Często potrzebujemy nie tylko uzyskać dane po konkretnym kluczu, ale też wypisać cały słownik. Do tego używa się metody entrySet().
for (var entry : phonebook.entrySet()) {
System.out.println(entry.getKey() + " -> " + entry.getValue());
}
Przykładowy wynik:
Alicja -> +10501112233
Dzięki temu od razu mamy dostęp zarówno do klucza (entry.getKey()), jak i do wartości (entry.getValue()).
7. Praktyka: zliczanie słów
Rozważmy klasyczny problem — zliczanie liczby wystąpień słów w tekście. To jeden z najbardziej obrazowych przykładów, po co w ogóle potrzebny jest HashMap.
String text = "java java core java";
HashMap<String, Integer> freq = new HashMap<String, Integer>();
for (String w : text.split(" "))
{
Integer old = freq.get(w);
freq.put(w, (old == null) ? 1 : old + 1);
}
System.out.println(freq);
Wynik:
{core=1, java=3}
Omówmy szczegółowo, co tu się dzieje:
- Podzieliliśmy łańcuch "java java core java" na słowa.
- Dla każdego słowa sprawdzamy, czy jest już w słowniku (freq.get(w)).
- Jeśli go nie ma (null), to pierwsze wystąpienie słowa → wstawiamy 1.
- Jeśli jest, to słowo już się pojawiło → zwiększamy wartość o jeden.
Praktyczne zastosowania:
- zliczanie liczby wywołań API,
- statystyka częstości słów w tekście,
- przechowywanie stanów towarów w magazynie.
8. Praktyka: książka telefoniczna
Napiszmy większą aplikację.
import java.util.HashMap;
import java.util.Scanner;
public class PhonebookApp {
public static void main(String[] args)
{
HashMap<String, String> phonebook = new HashMap<String, String>();
Scanner console = new Scanner(System.in);
while (true)
{
System.out.print("Wprowadź imię (lub pusty wiersz, aby wyjść): ");
String name = console.nextLine();
if (name.isEmpty()) break;
System.out.print("Wprowadź numer: ");
String phone = console.nextLine();
phonebook.put(name, phone);
}
System.out.println("Książka telefoniczna:");
for (var entry : phonebook.entrySet())
{
System.out.println(entry.getKey() + " -> " + entry.getValue());
}
}
}
Program działa jak mini-książka telefoniczna. Wprowadzisz imiona i numery, a one zostaną zapisane w HashMap. Na końcu można wypisać całą listę. Słowniki są bardzo często używane w realnych projektach.
GO TO FULL VERSION