Menu

HashMap w Javie: put, get, iterowanie i popularne wzorce

Jak używać HashMap w Javie do wyszukiwania po kluczu: put, get, getOrDefault, containsKey, iterowanie po wpisach i wzorce, po które sięga się najczęściej.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Mapa przechowuje pary klucz-wartość

HashMap (z java.util) przechowuje powiązania: każdy klucz wskazuje jedną wartość, a wartości wyszukujesz po kluczu w mniej więcej stałym czasie. Pomyśl o słowniku: słowo jest kluczem, a definicja wartością.

Dwa parametry typu to <KeyType, ValueType>. Tutaj klucze to String, a wartości to Integer. Podobnie jak przy ArrayList zmienną zwykle deklaruje się jako interfejs Map, a tworzy HashMap.

put, get i nadpisywanie

Dwie rzeczy warto zapamiętać:

  • Klucz jest unikalny. put z istniejącym kluczem zastępuje jego wartość i zwraca starą.
  • get dla brakującego klucza zwraca null, a nie błąd. Automatyczne rozpakowanie tego null do int rzuca NullPointerException, co jest częstym źródłem błędów.

getOrDefault omija pułapkę null

Zamiast za każdym razem sprawdzać null, poproś o wartość zapasową:

To najczystszy sposób obsługi wyszukiwań typu „może istnieje” i prowadzi prosto do najsłynniejszego wzorca z HashMap.

Liczenie wystąpień

Liczenie, ile razy pojawia się każdy element, to podręcznikowe zadanie dla HashMap:

Wzorzec map.put(key, map.getOrDefault(key, 0) + 1) czyta się jako „weź bieżącą liczbę (albo zero), dodaj jeden i zapisz z powrotem”. Zgrabniejszy odpowiednik to counts.merge(word, 1, Integer::sum).

Sprawdzanie i usuwanie

putIfAbsent(key, value) zapisuje wartość tylko wtedy, gdy klucza brakuje, co przydaje się przy leniwej inicjalizacji.

Pętla po HashMap

Najczęstsza pętla przechodzi po entrySet() i daje każdy klucz razem z wartością:

Jeśli potrzebujesz tylko kluczy albo tylko wartości:

Możesz też użyć forEach z lambdą: ages.forEach((name, age) -> System.out.println(name + ": " + age));.

HashMap nie zachowuje kolejności

HashMap nie gwarantuje żadnej kolejności iteracji: wynika ona z haszowania i może się zmieniać między uruchomieniami. Jeśli potrzebujesz przewidywalnej kolejności:

  • LinkedHashMap zachowuje kolejność wstawiania.
  • TreeMap utrzymuje klucze posortowane według porządku naturalnego (albo podanego przez ciebie Comparator).

Wszystkie trzy implementują interfejs Map, więc zamiana to zmiana jednego wiersza z konstruktorem.

Klucze muszą być haszowalne

HashMap znajduje wpisy przez haszowanie klucza, więc hashCode() i equals() klucza muszą być ze sobą zgodne. Typy wbudowane, takie jak String i Integer, robią to poprawnie. Jeśli jako klucza używasz własnej klasy, nadpisz zarówno equals, jak i hashCode. Inaczej dwa obiekty „równe” znaczeniowo trafią do różnych kubełków, a wyszukiwania będą zagadkowo zawodzić.

Dalej: HashSet

HashMap odpowiada na pytanie „jaka wartość jest zapisana pod tym kluczem?”. Gdy interesuje cię tylko to, czy coś w ogóle występuje, czyli zbiór unikalnych wartości bez powiązanych danych, narzędziem jest HashSet, omówiony na następnej stronie.

Najczęściej zadawane pytania

Jak utworzyć HashMap w Javie?

Zadeklaruj ją z dwoma parametrami typu, czyli typem klucza i typem wartości, i wywołaj konstruktor: Map<String, Integer> ages = new HashMap<>();. Potem dodawaj wpisy przez ages.put("Ada", 36); i odczytuj je przez ages.get("Ada");. Zaimportuj java.util.HashMap i java.util.Map.

Jak przejść pętlą po HashMap w Javie?

Przejdź pętlą for-each po map.entrySet(), aby dostać każdy klucz razem z wartością: for (Map.Entry<String, Integer> e : map.entrySet()) { ... }, odczytując e.getKey() i e.getValue(). Możesz też iterować po map.keySet(), gdy potrzebujesz tylko kluczy, albo po map.values(), gdy potrzebujesz tylko wartości. Pamiętaj, że HashMap nie zachowuje kolejności wstawiania.

Czym różni się get od getOrDefault?

get(key) zwraca wartość dla klucza albo null, jeśli klucza nie ma, co może prowadzić do NullPointerException, gdy od razu użyjesz wyniku. getOrDefault(key, fallback) zwraca wartość, jeśli istnieje, a w przeciwnym razie przekazaną wartość zapasową, więc unikasz sprawdzania null. Szczególnie przydaje się to przy liczeniu: counts.put(c, counts.getOrDefault(c, 0) + 1).

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ