Привет! Ранее мы разбирали структуры данных, где элементы хранятся сами по себе. В массиве, или списке ArrayList/LinkedList мы храним какое-то количество элементов.
Но что, если наша задача немного изменится? Например, представь себе, что перед нами стоит задача: создать список из 100 человек, где будет храниться ФИО человека и номер его паспорта. В принципе, это не так сложно. Например, можно уместить и то, и другое в строку, и создать список вот таких строк: “Анна Ивановна Решетникова, 4211 717171”. Но у такого решения сразу два недостатка. Во-первых, нам может понадобиться функция поиска по паспорту. А при таком формате хранения информации это будет проблематично. А во-вторых, ничто не помешает нам создать двух разных людей с одинаковыми номерами паспорта. И это самый серьезный недостаток нашего решения. Такие ситуации должны быть полностью исключены, не бывает двух людей с одинаковым номером паспорта. На помощь нам приходит новая структура данных — Map. Ее официальное русское название — “ассоциативный массив”, но его используют нечасто. Более распространены варианты “словарь”, “карта”, или (чаще всего) — сленговый англицизм “мапа” :) В чем ее принципиальное отличие от тех структур данных, которые мы рассматривали раньше? Прежде всего в том, что внутри Map данные хранятся в формате “ключ”-”значение”, то есть по парам. И в качестве ключей, и в качестве значений могут выступать любые объекты — числа, строки или объекты других классов. Мы сегодня рассмотрим самую распространенную реализацию Map — класс HashMap. Итак, что нам нужно про нее знать? Создается она очень просто:
public static void main(String[] args) {

   HashMap<Integer, String> passportsAndNames = new HashMap<>();

}
Здесь мы создали словарь, в котором элементы будут храниться в формате “число-строка”. Число будет выступать ключом, а строка — значением. Также мы указали какого типа у нас будут ключи (Integer), а какого — значения (String). Почему именно так? Во-первых, ключ в HashMap всегда является уникальным. Для нас это отлично подойдет, поскольку мы сможем использовать номер паспорта в качестве ключа и избежать повторов. А строка с ФИО будет выступать значением (ФИО у разных людей легко могут повторяться, в этом ничего страшного для нас нет). Добавление новой пары в HashMap выглядит так:
public class Main {

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


       passportsAndNames.put(212133, "Лидия Аркадьевна Бубликова");
       passportsAndNames.put(162348, "Иван Михайлович Серебряков");
       passportsAndNames.put(8082771, "Дональд Джон Трамп");
       System.out.println(passportsAndNames);

   }

}
Для этого используется метод put(). Кроме того, HashMap имеет переопределенный метод toString(), поэтому ее можно выводить на консоль. Вывод будет выглядеть так: {212133=Лидия Аркадьевна Бубликова, 8082771=Дональд Джон Трамп, 162348=Иван Михайлович Серебряков} Теперь давай проверим, действительно ли ключи являются уникальными? Попробуем добавить новый элемент с уже имеющимся в мапе ключом:
public static void main(String[] args) {

   HashMap<Integer, String> passportsAndNames = new HashMap<>();

   passportsAndNames.put(212133, "Лидия Аркадьевна Бубликова");
   passportsAndNames.put(162348, "Иван Михайлович Серебряков");
   passportsAndNames.put(8082771, "Дональд Джон Трамп");
   passportsAndNames.put(162348, "Виктор Михайлович Стычкин");//повторный ключ

   System.out.println(passportsAndNames);

}
Вывод: {212133=Лидия Аркадьевна Бубликова, 8082771=Дональд Джон Трамп, 162348=Виктор Михайлович Стычкин} Предыдущий элемент с ключом 162348, как видишь, был перезаписан. “Ключ” назвали ключом не просто так. Доступ к значениям в HashMap осуществляется по ключу (но никак не наоборот — ключ нельзя получить по значению, ведь значения могут быть повторяющимися). Это хорошо видно на примерах получения элемента, а также удаления элемента из HashMap:
public static void main(String[] args) {

   HashMap<Integer, String> passportsAndNames = new HashMap<>();

   passportsAndNames.put(212133, "Лидия Аркадьевна Бубликова");
   passportsAndNames.put(162348, "Иван Михайлович Серебряков");
   passportsAndNames.put(8082771, "Дональд Джон Трамп");

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


   passportsAndNames.remove(162348);
   System.out.println(passportsAndNames);

}
Для того, чтобы получить значение, или удалить пару из словаря, мы должны передать в методы get() и remove() именно уникальный ключ, соответствующий этому значению. Номерных индексов, как в массивах или списках, в HashMap нет — доступ к значению осуществляется по ключу. Вывод в консоль: Лидия Аркадьевна Бубликова {212133=Лидия Аркадьевна Бубликова, 8082771=Дональд Джон Трамп} В классах ArrayList и LinkedList мы могли проверить, содержится ли в списке какой-то конкретный элемент. HashMap тоже позволяет это делать, причем для обеих частей пары: у нее есть методы containtsKey()(проверяет наличие какого-то ключа) и containsValue() (проверяет наличие значения).
public static void main(String[] args) {

   HashMap<Integer, String> passportsAndNames = new HashMap<>();

   passportsAndNames.put(212133, "Лидия Аркадьевна Бубликова");
   passportsAndNames.put(162348, "Иван Михайлович Серебряков");
   passportsAndNames.put(8082771, "Дональд Джон Трамп");


   System.out.println(passportsAndNames.containsKey(11111));
   System.out.println(passportsAndNames.containsValue("Дональд Джон Трамп"));

}
Вывод: false true Еще одна удобная особенность HashMap — можно по-отдельности получить список всех ключей и всех значений. Для этого используются методы keySet() и values():
public class Main {

   public static void main(String[] args) {

       HashMap<Integer, String> passportsAndNames = new HashMap<>();

       passportsAndNames.put(212133, "Лидия Аркадьевна Бубликова");
       passportsAndNames.put(162348, "Иван Михайлович Серебряков");
       passportsAndNames.put(8082771, "Дональд Джон Трамп");

       Set<Integer> keys = passportsAndNames.keySet();
       System.out.println("Ключи: " + keys);

       ArrayList<String> values = new ArrayList<>(passportsAndNames.values());
       System.out.println("Значения: " + values);

   }

}
Ключи извлекаются в коллекцию Set, которую мы пока не проходили. Ее особенность в том, что в ней не может быть повторяющихся элементов. Сейчас главное запомни, что список всех ключей можно вынести из HashMap в отдельную коллекцию. Значения мы в примере сохранили в обычный ArrayList. Вывод в консоль: Ключи: [212133, 8082771, 162348] Значения: [Лидия Аркадьевна Бубликова, Дональд Джон Трамп, Иван Михайлович Серебряков] Методы size() и clear() делают ровно то же самое, что и в предыдущих структурах, которые мы проходили: первый — возвращает число элементов в словаре на текущий момент, второй — удаляет все элементы.
public static void main(String[] args) {

   HashMap<Integer, String> passportsAndNames = new HashMap<>();

   passportsAndNames.put(212133, "Лидия Аркадьевна Бубликова");
   passportsAndNames.put(162348, "Иван Михайлович Серебряков");
   passportsAndNames.put(8082771, "Дональд Джон Трамп");

   System.out.println(passportsAndNames.size());
   passportsAndNames.clear();
   System.out.println(passportsAndNames);

}
Вывод: 3 {} Для проверки того, есть ли в нашей HashMap хотя бы один элемент, можно использовать метод isEmpty():
public static void main(String[] args) {

   HashMap<Integer, String> passportsAndNames = new HashMap<>();

   passportsAndNames.put(212133, "Лидия Аркадьевна Бубликова");
   passportsAndNames.put(162348, "Иван Михайлович Серебряков");
   passportsAndNames.put(8082771, "Дональд Джон Трамп");

   if (!passportsAndNames.isEmpty()) {

       System.out.println(passportsAndNames);

   }

}
Вывод: {212133=Лидия Аркадьевна Бубликова, 8082771=Дональд Джон Трамп, 162348=Иван Михайлович Серебряков} Теперь вывод на консоль у нас будет осуществляться только после предварительной проверки:) Еще один интересный момент — две мапы можно объединить в одну. Для этого существует метод putAll(). Мы вызываем его у первой HashMap, передаем вторую в качестве аргумента, и элементы из второй будут добавлены в первую:
public static void main(String[] args) {

   HashMap<Integer, String> passportsAndNames = new HashMap<>();
   HashMap<Integer, String> passportsAndNames2 = new HashMap<>();

   passportsAndNames.put(212133, "Лидия Аркадьевна Бубликова");
   passportsAndNames.put(162348, "Иван Михайлович Серебряков");
   passportsAndNames.put(8082771, "Дональд Джон Трамп");

   passportsAndNames2.put(917352, "Алексей Андреевич Ермаков");
   passportsAndNames2.put(925648, "Максим Олегович Архаров");


   passportsAndNames.putAll(passportsAndNames2);
   System.out.println(passportsAndNames);

}
Вывод: {917352=Алексей Андреевич Ермаков, 212133=Лидия Аркадьевна Бубликова, 8082771=Дональд Джон Трамп, 925648=Максим Олегович Архаров, 162348=Иван Михайлович Серебряков} Все элементы passportsAndNames2 были скопированы в passportsAndNames. Теперь рассмотрим пример посложнее. А именно — перебор HashMap в цикле.
for (Map.Entry entry: passportsAndNames.entrySet()) {

   System.out.println(entry);

}
Класс Map.Entry обозначает раз пару “ключ-значение” внутри словаря. Метод entrySet() возвращает список всех пар в нашей HashMap (поскольку наша мапа состоит как раз из таких пар-Entry, то мы перебираем именно пары, а не отдельно ключи или значения). Вывод: 212133=Лидия Аркадьевна Бубликова 8082771=Дональд Джон Трамп 162348=Иван Михайлович Серебряков Сохрани себе на будущее вот эту статью: Структуры данных в картинках. HashMap Сейчас ее пока читать рановато, но в будущем, когда ты набьешь руку в использовании HashMap, она поможет тебе разобраться как эта структура данных устроена изнутри. Кроме того, не забудь изучить официальную документацию Oracle по HashMap.