В чем особенности Map
Что проверяют
Знаете ли вы, как реализации Map устроены внутри и как вы выбираете между ними. Определение знают все, поэтому следом почти всегда идут вопросы про hashCode и equals, про коллизии и про потокобезопасность.
Как отвечать
Map хранит пары ключ и значение с уникальными ключами и не наследует Collection. Дальше про реализации:
HashMap: массив корзин, индекс вычисляется изhashCodeключа. Начальная ёмкость 16, коэффициент загрузки 0.75, при превышении таблица растёт вдвое. С Java 8 корзина длиннее 8 элементов при таблице от 64 превращается в красно-чёрное дерево, поэтому худший случай поиска O(log n), а не O(n). Допускает одинnull-ключ, порядок не гарантирует;LinkedHashMap: плюс двусвязный список, хранит порядок вставки или, с флагомaccessOrder, порядок доступа. Вместе сremoveEldestEntryэто готовый LRU-кеш;TreeMap: красно-чёрное дерево, ключи отсортированы поComparableили переданномуComparator, операции O(log n). РеализуетNavigableMap:floorKey,ceilingKey,headMap,subMap;ConcurrentHashMap: потокобезопасна без общей блокировки,nullне принимает ни в ключах, ни в значениях,computeIfAbsentиmergeатомарны;Map.ofиMap.copyOf: неизменяемые, безnull, порядок обхода не определён.
С Java 21 у упорядоченных карт есть общий интерфейс SequencedMap с firstEntry, lastEntry и reversed().
Скажите и про контракт: ключ обязан согласованно реализовать equals и hashCode, а менять его поля после вставки нельзя, иначе элемент станет недостижим.
Где спотыкаются
Не могут объяснить, зачем переопределять оба метода. Если переопределён только equals, два равных ключа почти наверняка попадут в разные корзины.
Делают «проверить и вставить» двумя вызовами, containsKey и put, даже на ConcurrentHashMap. Между ними другой поток успеет вставить своё, для этого есть putIfAbsent и computeIfAbsent.
Путают get, вернувший null, с отсутствием ключа. Значение может быть null само по себе, для проверки есть containsKey, для значения по умолчанию getOrDefault.