Гид по технологиям

Как использовать Java HashMap: создание, чтение, обновление и удаление

• 5 min read • Java • Обновлено 04 Dec 2025
Java HashMap — CRUD, советы, примеры
Java HashMap — CRUD, советы, примеры

Студент, обучающийся программированию на Java

HashMap — это структура данных на основе пар «ключ–значение». Краткое определение: HashMap хранит элементы по ключу и обеспечивает амортизированно постоянное время доступа. Ключи и значения типизированы параметрами K и V соответственно. Класс java.util.HashMap расширяет AbstractMap и реализует интерфейс Map, поэтому предоставляет стандартные операции для работы с коллекцией.

Important: HashMap не гарантирует упорядоченность элементов при итерации. Если вам нужен упорядоченный по вставке порядок — смотрите LinkedHashMap; если нужен порядок по ключу — смотрите TreeMap.

Создание Java HashMap

По умолчанию HashMap создаётся с начальной вместимостью 16 и коэффициентом заполнения (load factor) 0.75. Есть четыре конструктора: пустой, с начальной вместимостью, с вместимостью и load factor, и копирующий из другой Map.

Пример использования конструктора по умолчанию:

import java.util.HashMap;

public class Main {
    public static void main(String[] args) {
        // создаём HashMap
        HashMap fruitsMap = new HashMap();
    }
}

В этом примере fruitsMap хранит Integer в качестве ключей и String в качестве значений. HashMap допускает значение null для ключа (один null-ключ) и для значений (много null-значений).

Добавление и хранение данных в HashMap

Метод put(K key, V value) добавляет или обновляет пару ключ–значение.

import java.util.HashMap;

public class Main {
    public static void main(String[] args) {
        HashMap fruitsMap = new HashMap();

        // добавляем элементы
        fruitsMap.put(3, "Pear");
        fruitsMap.put(6, "Mango");
        fruitsMap.put(7, "Plum");
        fruitsMap.put(4, "Apple");
        fruitsMap.put(1, "Orange");
        fruitsMap.put(5, "Berries");
        fruitsMap.put(2, "Melon");
    }
}

Заметка: порядок добавления не гарантирует порядок итерации. Консольный вывод может выглядеть упорядоченным для простых ключей, но это совпадение реализации, а не контракт класса.

Чтение данных из HashMap

Существует несколько способов получить данные в зависимости от задачи.

Получить весь объект HashMap

Простой способ увидеть содержимое — вывести объект:

System.out.println(fruitsMap);

Вывод покажет пары ключ=значение, но не обещает определённого порядка.

Итерация по элементам

Чтобы пройтись по всем парам, используйте entrySet():

for (HashMap.Entry fruit : fruitsMap.entrySet()) {
    System.out.println("Key: " + fruit.getKey() + " Value: " + fruit.getValue());
}

Этот цикл выведет все пары. Порядок может выглядеть сортированным для некоторых наборов ключей, но HashMap не гарантирует «сортировку».

Получить конкретное значение

Для получения значения по ключу используйте get():

System.out.println(fruitsMap.get(4)); // например: Apple

Если ключа нет, возвращается null (или заданное значение по умолчанию при использовании getOrDefault).

Обновление данных в HashMap

Для замены значения по ключу есть replace(). Две распространённые формы:

// заменить значение по ключу
fruitsMap.replace(4, "Grapes");
System.out.println(fruitsMap);

// заменить значение только если текущее равно ожидаемому
fruitsMap.replace(4, "Apple", "Grapes");
System.out.println(fruitsMap);

Дополнительные полезные методы: putIfAbsent, computeIfAbsent, compute.

Удаление данных из HashMap

Удалить конкретный элемент можно методом remove(K key) или remove(K key, V value). Очистить всю карту — clear().

fruitsMap.remove(5);
fruitsMap.remove(5, "Berries");
fruitsMap.clear();
System.out.println(fruitsMap); // {}

Поведение и производительность (ключевые детали)

  • Средняя сложность операций put/get/remove — O(1). В худшем случае (много коллизий) — O(n).
  • По умолчанию initialCapacity = 16, loadFactor = 0.75. Порог (threshold) для увеличения размера = capacity * loadFactor.
  • При превышении порога карта расширяется, обычно вдвое, и элементы перераспределяются.
  • В Java 8+ при большом числе коллизий корзины (buckets) преобразуются из связного списка в сбалансированное дерево (TreeNode) для ускорения поиска; порог для «treeify» обычно 8.
  • Важный контракт: корректная работа требует корректной реализации методов equals() и hashCode() у объектов-ключей.

Important: Не используйте изменяемые объекты в качестве ключей, если вы потом будете их изменять, — это приведёт к «потерянным» записям (ключ пересчитается, но старое место в бакете не будет найдено).

Когда HashMap не подходит — примеры неудач

  • Нужен потокобезопасный доступ из нескольких потоков без внешней синхронизации: HashMap не синхронен. Используйте ConcurrentHashMap или Collections.synchronizedMap.
  • Нужен упорядоченный вывод: используйте LinkedHashMap (порядок вставки) или TreeMap (порядок по ключу).
  • Ключи с плохими hashCode() (например, возвращают константу) вызовут деградацию производительности.

Сравнение с похожими коллекциями

  • HashMap vs Hashtable: Hashtable синхронизирован и устарел для большинства задач; HashMap быстрее в однопоточной среде.
  • HashMap vs LinkedHashMap: LinkedHashMap сохраняет порядок вставки или доступа.
  • HashMap vs TreeMap: TreeMap сортирует по ключу и обеспечивает логарифмическую сложность операций.

Лучшие практики и эвристики

  • Задавайте начальную вместимость, если заранее известен приблизительный размер, чтобы избежать частых расширений.
  • Реализуйте hashCode() равномерно и избегайте коллизий.
  • Не используйте изменяемые поля ключа после вставки в HashMap.
  • Для многопоточного окружения выбирайте ConcurrentHashMap.

Критерии приёмки

  • Создание: Map создаётся и пустой; size() == 0.
  • Добавление: put возвращает null при новой паре, size увеличивается.
  • Чтение: get возвращает ожидаемое значение для существующего ключа.
  • Обновление: replace изменяет значение; put перезаписывает существующее значение.
  • Удаление: remove удаляет пару; clear делает size() == 0.
  • Граничные случаи: работа с null-ключом и null-значениями проверена.

Мини‑чеклист для ролей

Для разработчика:

  • Проверить корректность equals() и hashCode() у ключей.
  • Оценить потребный размер и задать initialCapacity при создании.
  • Выбрать подходящую реализацию Map для задачи (HashMap/LinkedHashMap/TreeMap/ConcurrentHashMap).

Для ревьюера:

  • Убедиться, что нет использования изменяемых ключей.
  • Проверить реакции при null и крайние сценарии.
  • Оценить возможные проблемы конкурентного доступа.

Тестовые случаи / примеры приёмки

  • Добавить 1000 элементов, проверить, что все доступны по ключам.
  • Удалить несколько элементов, проверить размер и отсутствие по ключам.
  • Изменить значение у существующего ключа и проверить, что старое значение заменено.
  • Использовать getOrDefault для несуществующего ключа и проверить возвращаемое значение.
  • В многопоточном тесте проверить, что ConcurrentHashMap выдерживает параллельные записи без потерь (если требуется потокобезопасность).

Краткая шпаргалка по методам

  • put(K,V) — добавить или обновить.
  • get(K) — получить значение.
  • remove(K) / remove(K,V) — удалить.
  • containsKey(K), containsValue(V) — проверки.
  • size(), isEmpty(), clear() — управление размером.
  • replace(K,V), putIfAbsent(K,V), computeIfAbsent(K,Function).

1‑строчная глоссарная справка

  • Hashing — преобразование ключа в индекс для бакета.
  • Bucket — ячейка внутреннего массива, содержащая связанные записи или дерево.
  • Collision — две записи попали в один бакет.
  • Load factor — коэффициент заполнения, при котором происходит расширение.
  • Treeify — преобразование списка коллизий в дерево для ускорения поиска.

Короткое резюме

HashMap — быстрый и удобный словарь в Java. Он отлично подходит для большинства задач, требующих O(1) доступа по ключу, если ключи имеют корректный hashCode и нет требований к порядку или потокобезопасности. Выбирайте альтернативные реализации Map, если нужны сортировка, порядок вставки или конкурентный доступ.

Notes: Если вы готовите код для продакшена, добавьте юнит‑тесты на поведение с null, на конкурентные сценарии (при необходимости) и проверьте распределение hashCode у ваших доменных сущностей.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Несколько аккаунтов Skype: Multi Skype Launcher
Программное обеспечение

Несколько аккаунтов Skype: Multi Skype Launcher

Журнал для работы: повысить продуктивность
Productivity

Журнал для работы: повысить продуктивность

Персональные звуки уведомлений на Android
Android.

Персональные звуки уведомлений на Android

Скачивание шоу Hulu для офлайн‑просмотра
Стриминг

Скачивание шоу Hulu для офлайн‑просмотра

Microsoft Start: персонализированная новостная лента
Новости

Microsoft Start: персонализированная новостная лента

Как изменить имя в Epic Games быстро
Гайды

Как изменить имя в Epic Games быстро