00:00

Difference Between ArrayList and LinkedList in Java

Last updated: 5 min read

ArrayList and LinkedList both implement the List interface, so they offer the same methods and keep elements in insertion order. Their internals are completely different, which gives them very different performance:

  • ArrayList stores elements in a resizable array: instant access by index, but inserting or removing in the middle shifts elements.
  • LinkedList stores elements in a doubly linked list of nodes: cheap insertion and removal at the ends (and at a known node), but access by index walks the list.

In practice, ArrayList is the right default for almost all code. This page explains why.

1. Comparison Table

AspectArrayListLinkedList
Internal structureDynamic arrayDoubly linked list of nodes
get(i) / set(i)O(1)O(n) (walks from the nearer end)
Add at endAmortised O(1)O(1)
Add/remove at frontO(n) (shifts all elements)O(1)
Add/remove in the middleO(n) shiftO(n) to find the position, then O(1) relink (O(1) via an iterator)
Memory per elementOne reference (plus spare capacity)Node object with value, next and prev references (much more)
CPU cache friendlinessHigh (contiguous memory)Low (nodes scattered in the heap)
ImplementsList, RandomAccessList, Deque
Null elementsAllowedAllowed
Thread-safeNoNo

2. Same API, Different Capabilities

ListBehaviour.java
import java.util.*;

public class ListBehaviour {
    public static void main(String[] args) {
        List<String> array = new ArrayList<>(List.of("B", "C", "D"));
        LinkedList<String> linked = new LinkedList<>(List.of("B", "C", "D"));

        // Same List API, same results
        array.add(0, "A");   linked.add(0, "A");
        array.remove("C");   linked.remove("C");
        System.out.println("ArrayList : " + array + ", get(2) = " + array.get(2));
        System.out.println("LinkedList: " + linked + ", get(2) = " + linked.get(2));

        // LinkedList is also a Deque: cheap operations at both ends
        linked.addFirst("start");
        linked.addLast("end");
        System.out.println("Deque ops : " + linked + ", pollFirst = " + linked.pollFirst() + ", peekLast = " + linked.peekLast());

        System.out.println("RandomAccess? ArrayList " + (array instanceof RandomAccess)
                           + ", LinkedList " + (linked instanceof RandomAccess));
    }
}
Output
ArrayList : [A, B, D], get(2) = D
LinkedList: [A, B, D], get(2) = D
Deque ops : [start, A, B, D, end], pollFirst = start, peekLast = end
RandomAccess? ArrayList true, LinkedList false

Both lists produce identical results through the List interface. LinkedList additionally implements Deque, with methods like addFirst, pollFirst and peekLast.

3. Performance in Practice

A small benchmark with 100,000 elements:

ListBenchmark.java
import java.util.*;

public class ListBenchmark {
    static long ms(Runnable r) { long s = System.nanoTime(); r.run(); return (System.nanoTime() - s) / 1_000_000; }

    public static void main(String[] args) {
        int n = 100_000;
        List<Integer> array = new ArrayList<>(), linked = new LinkedList<>();
        for (int i = 0; i < n; i++) { array.add(i); linked.add(i); }

        long arrGet = ms(() -> { long sum = 0; for (int i = 0; i < 20_000; i++) sum += array.get(i * 5); });
        long linkGet = ms(() -> { long sum = 0; for (int i = 0; i < 20_000; i++) sum += linked.get(i * 5); });

        long arrFront = ms(() -> { for (int i = 0; i < 20_000; i++) array.add(0, i); });
        long linkFront = ms(() -> { for (int i = 0; i < 20_000; i++) ((LinkedList<Integer>) linked).addFirst(i); });

        System.out.printf("random get(i) x20k : ArrayList %4d ms | LinkedList %5d ms%n", arrGet, linkGet);
        System.out.printf("insert at front x20k: ArrayList %4d ms | LinkedList %5d ms%n", arrFront, linkFront);
    }
}
Output (sample run; timings vary by machine)
random get(i) x20k : ArrayList    0 ms | LinkedList   749 ms
insert at front x20k: ArrayList  159 ms | LinkedList     0 ms
  • Index-based access is dramatically slower on LinkedList; a for (int i...) list.get(i) loop over it is O(n²).
  • Inserting at the front favours LinkedList, but ArrayDeque does that even better.
  • For iteration and appending, ArrayList is usually faster thanks to contiguous memory, even where big-O suggests a tie.

4. When to Use Which

  • Use ArrayList by default: reading by index, iterating, appending, sorting, typical business data.
  • Consider LinkedList only when you frequently insert or remove elements through an iterator in the middle of large lists, or need a list that is also a deque.
  • For queues and stacks, prefer ArrayDeque, which is faster than LinkedList and uses less memory.

5. Summary

  • ArrayList is array-backed: O(1) index access, O(n) insertions and removals in the middle or front.
  • LinkedList is node-based: O(1) operations at the ends, O(n) index access, higher memory use.
  • Both implement List; LinkedList also implements Deque.
  • Choose ArrayList in almost all cases, and ArrayDeque for queue-like use.

Related Tutorials