В каких ситуациях LinkedList стоит использовать не из-за производительности, а из-за интерфейсов или особенностей
Что проверяют
Знаете ли вы LinkedList глубже фразы «вставка за O(1)»: какие контракты он реализует и чем его поведение отличается от ArrayList и ArrayDeque. Следом часто спрашивают, почему в новом коде он встречается редко и что изменилось в Java 21.
Как отвечать
Сразу оговорите, что по скорости LinkedList почти всегда проигрывает: каждый элемент это отдельный узел с двумя ссылками, данные разбросаны по памяти, доступ по индексу линейный. Поэтому речь именно о свойствах:
- один объект и
List, иDeque: нужен код, который работает со структурой и по индексу, и как с двусторонней очередью черезaddFirst,pollLast,descendingIterator().ArrayListне очередь,ArrayDequeне список; - допускает
null:ArrayDequeнаnullбросаетNullPointerException, аLinkedListего хранит. Если в очереди по смыслу бывают пустые значения, это аргумент; - правка через
ListIterator:add,removeиsetв текущей позиции во время обхода выполняются за константу, без сдвига хвоста. Это единственный честный случай «быстрой вставки в середину»: когда вы уже стоите в нужном месте; - нет ёмкости: не бывает разового копирования большого массива при росте, и после удалений память не держится впустую, как у
ArrayListбезtrimToSize().
Упомяните Java 21: интерфейс SequencedCollection дал getFirst, getLast, addFirst, removeLast и reversed() всем спискам, включая ArrayList. Часть поводов брать LinkedList ради удобных методов пропала.
Где спотыкаются
Говорят, что list.add(index, e) у связного списка быстрый. До позиции сначала надо дойти, это O(n), и на практике ArrayList с System.arraycopy обычно выигрывает.
Называют сохранение порядка особенностью LinkedList. Порядок вставки хранит любой List.
Предлагают LinkedList как очередь для нескольких потоков. Он не потокобезопасен, для этого есть ConcurrentLinkedDeque и LinkedBlockingQueue. И забывают, что при null внутри poll() уже не отличает пустую очередь от пустого элемента.