Чем отличается SortedMap от LinkedHashMap в Java?

Ответ

Обе реализации Map, но с разными гарантиями порядка итерации.

SortedMap (Интерфейс, реализация — TreeMap)

  • Гарантия порядка: Элементы автоматически сортируются по ключам.
  • Критерий сортировки: Естественный порядок (Comparable) или внешний Comparator.
  • Производительность: Основные операции (put, get, remove) — O(log n).
  • Использование: Когда требуется порядок по ключу (например, вывод от A до Z, от 1 до 10).
    SortedMap<Integer, String> sortedMap = new TreeMap<>();
    sortedMap.put(3, "Three");
    sortedMap.put(1, "One");
    sortedMap.put(2, "Two");
    // Итерация будет по ключам: 1, 2, 3
    System.out.println(sortedMap); // {1=One, 2=Two, 3=Three}

LinkedHashMap

  • Гарантия порядка: Сохраняет порядок вставки элементов (по умолчанию). Также может сохранять порядок доступа (при accessOrder=true).
  • Критерий сортировки: Отсутствует. Порядок определяется историей операций с map.
  • Производительность: Основные операции — O(1) (как у HashMap, но с небольшими накладными расходами на поддержание двусвязного списка).
  • Использование: Когда важен порядок добавления (кэш LRU, сохранение последовательности обработки).

    // Порядок вставки
    LinkedHashMap<Integer, String> linkedMap = new LinkedHashMap<>();
    linkedMap.put(3, "Three");
    linkedMap.put(1, "One");
    linkedMap.put(2, "Two");
    // Итерация будет: 3, 1, 2 (как добавляли)
    System.out.println(linkedMap); // {3=Three, 1=One, 2=Two}
    
    // LRU-кэш (порядок доступа)
    LinkedHashMap<Integer, String> lruCache = new LinkedHashMap<>(16, 0.75f, true) {
        @Override
        protected boolean removeEldestEntry(Map.Entry<Integer, String> eldest) {
            return size() > 100; // Удаляет самый старый элемент при превышении лимита
        }
    };

Выбор: Нужна сортировка по ключу → TreeMap. Нужен порядок вставки или LRU-кэш → LinkedHashMap.

Ответ 18+ 🔞

Давай разберём эту дичь, а то голова уже пухнет от этих ваших интерфейсов. Смотри, есть две штуки, которые оба Map, но ведут себя как два разных мудака в одной очереди.

SortedMap (а по сути — TreeMap, его главный пахан)

  • Что гарантирует? Что все элементы будут автоматически отсортированы по ключам. Сам, сука, всё расставит по полочкам. Добавил ты там 3, 1, 2 — а он тебе на выходе 1, 2, 3. Красота, блядь.
  • Как сортирует? Либо по естественному порядку (если ключи Comparable), либо ты ему свой Comparator подсовываешь, и он уже по твоим правилам пляшет.
  • Скорость? Основные операции — put, get, remove — будут O(log n). Не огонь, но и не пиздец. Дерево же, ёпта.
  • Когда юзать? Когда тебе нахуй нужен порядок по ключу. Вывести от А до Я, от 1 до 100, от самого маленького дебила до самого большого — вот сюда.
SortedMap<Integer, String> sortedMap = new TreeMap<>();
sortedMap.put(3, "Three");
sortedMap.put(1, "One");
sortedMap.put(2, "Two");
// Итерация будет по ключам: 1, 2, 3
System.out.println(sortedMap); // {1=One, 2=Two, 3=Three}

LinkedHashMap

  • Что гарантирует? Сохраняет порядок, в котором ты всё засунул. По умолчанию — порядок вставки. А ещё у него есть режим хитрожопости — порядок доступа (accessOrder=true). То есть какой элемент тронули — тот в конец очереди и ушёл.
  • Как сортирует? Никак, блядь! Он не сортирует. Он просто помнит, в каком порядке ты ему всё совал или к чему потом лапался.
  • Скорость? O(1) в среднем, почти как у HashMap, только с маленькой довесочиной за поддержание своего внутреннего двусвязного списка. Вротберунчик, но быстрый.
  • Когда юзать? Когда тебе важен порядок добавления. Или когда пишешь какой-нибудь LRU-кэш, чтобы старый хлам выкидывать.
// Порядок вставки
LinkedHashMap<Integer, String> linkedMap = new LinkedHashMap<>();
linkedMap.put(3, "Three");
linkedMap.put(1, "One");
linkedMap.put(2, "Two");
// Итерация будет: 3, 1, 2 (как добавляли)
System.out.println(linkedMap); // {3=Three, 1=One, 2=Two}

// LRU-кэш (порядок доступа) — вот это уже поинтереснее
LinkedHashMap<Integer, String> lruCache = new LinkedHashMap<>(16, 0.75f, true) {
    @Override
    protected boolean removeEldestEntry(Map.Entry<Integer, String> eldest) {
        return size() > 100; // Удалит самого древнего мудака, если лимит превысили
    }
};

Короче, выбор-то какой, ёпта? Нужно, чтобы всё само по ключам разложилось красиво — TreeMap (он же SortedMap). Нужно, чтобы всё лежало как ты клал, или чтобы кэш работал по принципу «кто давно не трогал — того нахуй» — LinkedHashMap. Всё остальное — в HashMap и не париться.