<code>LinkedList</code> in Java β€” Doubly Linked List

LinkedList is a doubly-linked list that also implements Deque. On paper, that's attractive: O(1) insert/remove at both ends. In practice, cache locality kills it β€” ArrayList beats LinkedList at almost every real workload, including head and tail operations for small lists.

API (when you insist)

var list = new LinkedList<String>();
list.addFirst("a");               // at head β€” O(1)
list.addLast("b");                // at tail β€” O(1)
list.add("c");                    // same as addLast
list.get(0);                      // O(n) β€” random access is SLOW
list.peekFirst();                 // head, or null
list.pollLast();                  // remove and return tail
list.removeFirst();               // throws if empty

Why it's rarely the right choice

OperationArrayListLinkedList
Random access get(i)O(1) β€” cache-friendlyO(n)
Add at endAmortised O(1)O(1)
Add at startO(n)O(1)
Memory overhead per element~4-8 bytes~32-48 bytes (two pointers + object header)
Cache localityExcellentPoor β€” every node allocated separately

Modern CPUs fetch memory in 64-byte lines. ArrayList's contiguous data blazes through; LinkedList chases pointers and misses the cache on almost every step.

When LinkedList could win

  • Extremely large lists where you insert/remove mostly in the middle, through an existing ListIterator that already holds the position.
  • Legacy APIs that return LinkedList.

For queue-like usage, ArrayDeque is faster than LinkedList for both FIFO and LIFO. The JDK itself uses ArrayDeque in BlockingQueue implementations.

Common mistakes

  • Picking LinkedList because "linked = fast inserts" β€” cache locality usually wins. Benchmark before choosing.
  • Calling get(i) in a loop β€” each call is O(n), so the loop is O(nΒ²). Use for-each or an Iterator.
  • Using as a queue β€” ArrayDeque is strictly better.

Related

Pillar: Java collections. Prefer ArrayList or ArrayDeque.