Как итерироваться по Map в Java, чтобы получить ключ и значение
Что проверяют
Базу коллекций: знаете ли вы про entrySet() и почему он лучше пары keySet() плюс get(). Почти всегда следом спрашивают, как удалить элемент во время обхода и в каком порядке придут ключи.
Как отвечать
Назовите основные способы и когда какой уместен:
entrySet()в for-each:for (Map.Entry<String, Integer> e : map.entrySet()), дальшеe.getKey()иe.getValue(). С Java 10 можно писатьfor (var e : map.entrySet()). Это основной вариант: один проход без повторных поисков;forEach:map.forEach((k, v) -> ...)с Java 8. Короче всего, но из лямбды не выйти черезbreakи не изменить локальную переменную снаружи;- стримы:
map.entrySet().stream()сfilter,sorted(Map.Entry.comparingByValue())иcollect, когда нужна обработка, а не просто обход; keySet()сget(): работает, но на каждый ключ делает лишний поиск. ВHashMapэто в среднем O(1), вTreeMapуже O(log n), плюс лишний код.
Про изменение во время обхода. Если вызвать map.remove() внутри for-each по HashMap, итератор бросит ConcurrentModificationException. Удалять правильно через Iterator.remove() или одной строкой map.entrySet().removeIf(e -> e.getValue() == 0). Поменять значение можно прямо в обходе через e.setValue(), если реализация это поддерживает: у неизменяемых Map.of() будет UnsupportedOperationException.
Про порядок. HashMap порядка не гарантирует, LinkedHashMap отдаёт элементы в порядке вставки, TreeMap в порядке сортировки ключей. С Java 21 у упорядоченных словарей есть интерфейс SequencedMap с firstEntry(), lastEntry() и reversed(). ConcurrentHashMap при обходе исключение не бросает: её итератор слабо согласованный и может не увидеть параллельные изменения.
Где спотыкаются
Итерируют по keySet() и дёргают get(), а на вопрос «почему не entrySet()» ответить не могут.
Удаляют элементы через map.remove() внутри цикла и удивляются исключению. Или, что хуже, ловят его и продолжают.
Рассчитывают на порядок элементов в HashMap. На маленьких данных в тестах он кажется стабильным, а после роста таблицы или смены версии JDK меняется.