<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
| Operation | ArrayList | LinkedList |
|---|---|---|
Random access get(i) | O(1) β cache-friendly | O(n) |
| Add at end | Amortised O(1) | O(1) |
| Add at start | O(n) | O(1) |
| Memory overhead per element | ~4-8 bytes | ~32-48 bytes (two pointers + object header) |
| Cache locality | Excellent | Poor β 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
ListIteratorthat 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
LinkedListbecause "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Β²). Usefor-eachor anIterator. - Using as a queue β
ArrayDequeis strictly better.
Related
Pillar: Java collections. Prefer ArrayList or ArrayDeque.