CodeGym/Blog Java/Poland/HashMap: jaki to rodzaj mapy?
Autor
Milan Vucic
Programming Tutor at Codementor.io

HashMap: jaki to rodzaj mapy?

Opublikowano w grupie Poland
Cześć! W tej lekcji przyjrzymy się bliżej Java HashMap. Wcześniej studiowaliśmy struktury danych, w których elementy są przechowywane jako one same. W tablicy lub ArrayList/LinkedList przechowujemy pewną liczbę elementów. Co jednak, jeśli nasze zadanie nieco się zmieni? Wyobraź sobie następujące zadanie: utwórz listę 100 osób, która przechowuje nazwisko i numer paszportu każdej osoby. W zasadzie nie jest to takie trudne. Na przykład możesz wypchnąć oba w ciąg, a następnie utworzyć listę tych ciągów:
"Amelia Aguilar, 4211 717171".
Rozwiązanie to ma jednak dwie wady. Po pierwsze, możemy potrzebować możliwości wyszukiwania według numeru paszportu. I to będzie problematyczne, biorąc pod uwagę ten format przechowywania informacji. Po drugie, nic nie stoi na przeszkodzie, aby stworzyć dwie różne osoby z tym samym numerem paszportu. I to jest najpoważniejszy mankament naszego rozwiązania. To nigdy nie powinno być dozwolone: żadne dwie osoby nie mają tego samego numeru paszportu. Z pomocą przychodzi nam nowa struktura danych: Mapa. Jest również znany jako "tablica asocjacyjna", ale ten termin jest rzadko używany. Bardziej potocznie nazywa się to "słownikiem" lub "mapą" :) Jak zasadniczo różni się od struktur danych, które rozważaliśmy wcześniej? Przede wszystkim w tym, że dane w Map przechowywane są jako pary klucz-wartość. Jako klucze i wartości mogą służyć dowolne rzeczy: liczby, ciągi znaków lub obiekty innych klas. Dziś przestudiujemy najczęściej spotykaną implementację klasy Map: Java HashMap. HashMap: jaki to rodzaj mapy? - 2

Co zatem musimy wiedzieć o HashMap w Javie?

Tworzenie jej jest bardzo proste:
public static void main(String[] args) {
   HashMap<Integer, String> passportsAndNames = new HashMap<>();
}

Tutaj tworzymy słownik, który przechowuje elementy jako pary „liczba-ciąg". Liczba będzie działać jako klucz, a ciąg jako wartość. Określamy również typ klucza (Integer) i typ wartości (String). Dlaczego? Po pierwsze, klucz HashMap jest zawsze unikalny. To nam doskonale odpowiada, ponieważ możemy użyć numeru paszportu jako klucza i uniknąć duplikatów. Wartością będzie ciąg znaków z pełnym imieniem i nazwiskiem (różne osoby mogą mieć to samo imię i nazwisko; nie jest to nic, czym moglibyśmy się przejmować). Dodanie nowej pary do HashMap wygląda tak:

public class Main {

   public static void main(String[] args) {
       HashMap<Integer, String> passportsAndNames = new HashMap<>();

       passportsAndNames.put (212133, "Bridget Logan");
       passportsAndNames.put (162348, "Ivan the Great");
       passportsAndNames.put(8082771, "Donald John Trump");
       System.out.println(passportsAndNames);
   }
}
Używamy do tego metody put(). Dodatkowo HashMap nadpisuje metodę toString(), dzięki czemu można ją wyświetlić na konsoli. Dane wyjściowe będą wyglądały tak:
{212133=Bridget Logan, 8082771=Donald John Trump, 162348=Ivan the Great}
Teraz sprawdźmy, czy klucze są rzeczywiście unikalne? Spróbujmy dodać nowy element z kluczem, który został już użyty w mapie:
public static void main(String[] args) {
   HashMap<Integer, String> passportsAndNames = new HashMap<>();

   passportsAndNames.put (212133, "Bridget Logan");
   passportsAndNames.put (162348, "Ivan the Great");
   passportsAndNames.put(8082771, "Donald John Trump");
   passportsAndNames.put(162348, "Albert Kent");// This key has already been used
   System.out.println(passportsAndNames);
}
Output:
{212133=Bridget Logan, 8082771=Donald John Trump, 162348=Albert Kent}
Jak widać, poprzednia wartość związana z kluczem 162348 została nadpisana. Nie bez powodu używamy określenia "klucz". Wartości w HashMap są dostępne przy użyciu klucza, ale nie na odwrót. Klucz nie może być uzyskany za pomocą wartości, ponieważ wartości mogą nie być unikalne. Widać to wyraźnie podczas pobierania lub usuwania elementu z HashMap:
public static void main(String[] args) {
   HashMap<Integer, String> passportsAndNames = new HashMap<>();

   passportsAndNames.put (212133, "Bridget Logan");
   passportsAndNames.put (162348, "Ivan the Great");
   passportsAndNames.put(8082771, "Donald John Trump");

   String lidiaName = passportsAndNames.get(212133);
   System.out.println(lidiaName);

   passportsAndNames.remove(162348);
   System.out.println(passportsAndNames);
}
Aby uzyskać wartość lub usunąć parę ze słownika, musimy przekazać do funkcji get() and remove() unikalny klucz odpowiadający wartości. W przeciwieństwie do tablic i list, HashMap w Javie nie ma indeksów numerycznych: dostęp do wartości odbywa się za pomocą klucza. Wyświetlone zostanie:
Bridget Logan {212133=Bridget Logan, 8082771=Donald John Trump}
Klasy ArrayList i LinkedList pozwalają nam sprawdzić, czy lista zawiera jakiś konkretny element. Java HashMap pozwala nam to zrobić. Co więcej, możemy to zrobić dla obu członków pary: Do tego służą metody containsKey() (sprawdza klucz) i containsValue() (sprawdza wartość).
public static void main(String[] args) {
   HashMap<Integer, String> passportsAndNames = new HashMap<>();

   passportsAndNames.put (212133, "Bridget Logan");
   passportsAndNames.put (162348, "Ivan the Great");
   passportsAndNames.put(8082771, "Donald John Trump");

   System.out.println(passportsAndNames.containsKey(11111));
   System.out.println(passportsAndNames.containsValue("Donald John Trump"));
}
Wyjście:
false true
Inną wygodną cechą HashMap w Javie jest fakt, że można uzyskać oddzielne listy wszystkich kluczy i wszystkich wartości. Służą do tego metody keySet() and values():
public class Main {

   public static void main(String[] args) {
       HashMap<Integer, String> passportsAndNames = new HashMap<>();

       passportsAndNames.put (212133, "Bridget Logan");
       passportsAndNames.put (162348, "Ivan the Great");
       passportsAndNames.put(8082771, "Donald John Trump");

       Set keys = passportsAndNames.keySet();
       System.out.println("Keys: " + keys);

       ArrayList<String> values = new ArrayList<>(passportsAndNames.values());
       System.out.println("Values: " + values);
   }
}
Klucze są wyodrębniane w Set, którego jeszcze nie objęliśmy. Jest on o tyle szczególny, że nie może zawierać elementów powtarzających się. Teraz najważniejsze jest, aby pamiętać, że lista wszystkich kluczy może być pobierana z HashMap do oddzielnej kolekcji. W przykładzie zapisaliśmy wartości do zwykłej ArrayList. Wyświetlone zostanie:
Keys: [212133, 8082771, 162348] Values: [Bridget Logan, Donald John Trump, Ivan the Great]
Metody size() and clear() robią dokładnie to samo, co w poprzednich omawianych strukturach: pierwsza zwraca liczbę elementów znajdujących się aktualnie w słowniku, druga usuwa wszystkie elementy.
public static void main(String[] args) {
   HashMap<Integer, String> passportsAndNames = new HashMap<>();

   passportsAndNames.put (212133, "Bridget Logan");
   passportsAndNames.put (162348, "Ivan the Great");
   passportsAndNames.put(8082771, "Donald John Trump");

   System.out.println(passportsAndNames.size());
   passportsAndNames.clear();
   System.out.println(passportsAndNames);
}
Wydruk:
3 {}
HashMap: jaki to rodzaj mapy? - 2Aby sprawdzić czy w naszej HashMap jest przynajmniej jeden element, możemy użyć metody isEmpty():
public static void main(String[] args) {
   HashMap<Integer, String> passportsAndNames = new HashMap<>();

   passportsAndNames.put (212133, "Bridget Logan");
   passportsAndNames.put (162348, "Ivan the Great");
   passportsAndNames.put(8082771, "Donald John Trump");

   if (!passportsAndNames.isEmpty()) {

       System.out.println(passportsAndNames);
   }
}
Output:
{212133=Bridget Logan, 8082771=Donald John Trump, 162348=Ivan the Great}
Teraz będziemy wyprowadzać na konsolę tylko po wstępnym sprawdzeniu :) Kolejnym ciekawym punktem jest możliwość połączenia dwóch Map w jedną. Dokonujemy tego za pomocą metody putAll(). Wywołujemy ją na pierwszej HashMap, przekazujemy drugą jako argument, a elementy z drugiej są dodawane do pierwszej:
public static void main(String[] args) {
   HashMap<Integer, String> passportsAndNames = new HashMap<>();
   HashMap<Integer, String> passportsAndNames2 = new HashMap<>();

   passportsAndNames.put (212133, "Bridget Logan");
   passportsAndNames.put (162348, "Ivan the Great");
   passportsAndNames.put(8082771, "Donald John Trump");

   passportsAndNames2.put(917352, "Clifford Patrick");
   passportsAndNames2.put(925648, "Mitchell Salgado");

   passportsAndNames.putAll(passportsAndNames2);
   System.out.println(passportsAndNames);
}
Output:
{917352=Clifford Patrick, 212133=Bridget Logan, 8082771=Donald John Trump, 925648=Mitchell Salgado, 162348=Ivan the Great}
Wszystkie pary z passportsAndNames2 zostały skopiowane do passportsAndNames. Rozważmy teraz bardziej skomplikowany przykład. W szczególności, iteracja nad HashMap w pętli.
for (Map.Entry<Integer, String> entry: passportsAndNames.entrySet()) {
   System.out.println(entry);
}
Klasa Map.Entry oznacza parę klucz-wartość wewnątrz słownika. Metoda entrySet() zwraca listę wszystkich par w naszej HashMap. Ponieważ nasza mapa składa się z tych par Map.Entry, iterujemy po parach, a nie oddzielnych kluczach lub wartościach. Wydruk:
212133=Bridget Logan 8082771=Donald John Trump 162348=Ivan the Great
Nie zapomnij również przestudiować oficjalnej dokumentacji Oracle dla HashMap.
Komentarze
  • Popularne
  • Najnowsze
  • Najstarsze
Musisz się zalogować, aby dodać komentarz
Ta strona nie ma jeszcze żadnych komentarzy