Fundamentals 15 min read

Detailed Analysis of Java LinkedList Implementation (JDK 1.8)

This article provides a detailed examination of the JDK 1.8 LinkedList class, covering its internal fields, constructors, node structure, and core methods for adding, retrieving, and removing elements, while highlighting performance characteristics and differences from ArrayList.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Detailed Analysis of Java LinkedList Implementation (JDK 1.8)

LinkedList is an ordered sequence implemented as a doubly‑linked list. It allows efficient insertion and removal at any position, is not thread‑safe, and permits null elements.

Source Code Overview

1. Fields

/**
 * Number of elements in the list
 */
transient int size = 0;

/**
 * Pointer to first node
 * Invariant: (first == null && last == null) ||
 *            (first.prev == null && first.item != null)
 */
transient Node
first;

/**
 * Pointer to last node
 * Invariant: (first == null && last == null) ||
 *            (last.next == null && last.item != null)
 */
transient Node
last;

2. Constructors

/**
 * No‑arg constructor
 */
public LinkedList() {}

/**
 * Constructs a list containing the elements of the specified collection, in the order they are returned by the collection's iterator.
 */
public LinkedList(Collection
c) {
    this();
    addAll(c);
}

3. Node Class

private static class Node
{
    // element value
    E item;
    // next node
    Node
next;
    // previous node
    Node
prev;

    Node(Node
prev, E element, Node
next) {
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}

Because each node holds both prev and next , the structure is a doubly‑linked list.

4. Adding Elements

addAll(Collection c)

Appends all elements of collection c to the end of the list. If addAll(int index, Collection c) is used, the elements are inserted after the specified index.
public boolean addAll(Collection
c) {
    return addAll(size, c);
}

public boolean addAll(int index, Collection
c) {
    checkPositionIndex(index);
    Object[] a = c.toArray();
    int numNew = a.length;
    if (numNew == 0) return false;
    Node
pred, succ;
    if (index == size) {
        succ = null;
        pred = last;
    } else {
        succ = node(index);
        pred = succ.prev;
    }
    for (Object o : a) {
        @SuppressWarnings("unchecked")
        E e = (E) o;
        Node
newNode = new Node<>(pred, e, null);
        if (pred == null)
            first = newNode;
        else
            pred.next = newNode;
        pred = newNode;
    }
    if (succ == null) {
        last = pred;
    } else {
        pred.next = succ;
        succ.prev = pred;
    }
    size += numNew;
    modCount++;
    return true;
}

addFirst(E e)

Inserts the element at the head of the list.
public void addFirst(E e) {
    linkFirst(e);
}

private void linkFirst(E e) {
    final Node
f = first;
    final Node
newNode = new Node<>(null, e, f);
    first = newNode;
    if (f == null)
        last = newNode;
    else
        f.prev = newNode;
    size++;
    modCount++;
}

addLast(E e)

Inserts the element at the tail of the list.
public void addLast(E e) {
    linkLast(e);
}

void linkLast(E e) {
    final Node
l = last;
    final Node
newNode = new Node<>(l, e, null);
    last = newNode;
    if (l == null)
        first = newNode;
    else
        l.next = newNode;
    size++;
    modCount++;
}

add(E e)

Appends the element to the end of the list.
public boolean add(E e) {
    linkLast(e);
    return true;
}

add(int index, E element)

Inserts element at the specified position.
public void add(int index, E element) {
    checkPositionIndex(index);
    if (index == size)
        linkLast(element);
    else
        linkBefore(element, node(index));
}

void linkBefore(E e, Node
succ) {
    final Node
pred = succ.prev;
    final Node
newNode = new Node<>(pred, e, succ);
    succ.prev = newNode;
    if (pred == null)
        first = newNode;
    else
        pred.next = newNode;
    size++;
    modCount++;
}

5. Accessing Elements

get(int index)

Returns the element at the specified position.
public E get(int index) {
    checkElementIndex(index);
    return node(index).item;
}

private Node
node(int index) {
    // if index is in first half, start from first
    if (index < (size >> 1)) {
        Node
x = first;
        for (int i = 0; i < index; i++)
            x = x.next;
        return x;
    } else { // start from last
        Node
x = last;
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}

getFirst() / getLast()

public E getFirst() {
    final Node
f = first;
    if (f == null) throw new NoSuchElementException();
    return f.item;
}

public E getLast() {
    final Node
l = last;
    if (l == null) throw new NoSuchElementException();
    return l.item;
}

6. Removing Elements

remove(Object o)

Removes the first occurrence of the specified element.
public boolean remove(Object o) {
    if (o == null) {
        for (Node
x = first; x != null; x = x.next) {
            if (x.item == null) {
                unlink(x);
                return true;
            }
        }
    } else {
        for (Node
x = first; x != null; x = x.next) {
            if (o.equals(x.item)) {
                unlink(x);
                return true;
            }
        }
    }
    return false;
}

E unlink(Node
x) {
    final E element = x.item;
    final Node
next = x.next;
    final Node
prev = x.prev;
    if (prev == null) {
        first = next;
    } else {
        prev.next = next;
        x.prev = null;
    }
    if (next == null) {
        last = prev;
    } else {
        next.prev = prev;
        x.next = null;
    }
    x.item = null;
    size--;
    modCount++;
    return element;
}

remove(int index)

public E remove(int index) {
    checkElementIndex(index);
    return unlink(node(index));
}

removeFirst() / removeLast()

public E removeFirst() {
    final Node
f = first;
    if (f == null) throw new NoSuchElementException();
    return unlinkFirst(f);
}

private E unlinkFirst(Node
f) {
    final E element = f.item;
    final Node
next = f.next;
    f.item = null;
    f.next = null;
    first = next;
    if (next == null)
        last = null;
    else
        next.prev = null;
    size--;
    modCount++;
    return element;
}

public E removeLast() {
    final Node
l = last;
    if (l == null) throw new NoSuchElementException();
    return unlinkLast(l);
}

private E unlinkLast(Node
l) {
    final E element = l.item;
    final Node
prev = l.prev;
    l.item = null;
    l.prev = null;
    last = prev;
    if (prev == null)
        first = null;
    else
        prev.next = null;
    size--;
    modCount++;
    return element;
}

7. Modifying Elements

public E set(int index, E element) {
    checkElementIndex(index);
    Node
x = node(index);
    E oldVal = x.item;
    x.item = element;
    return oldVal;
}

8. Comparison with ArrayList

Advantages of LinkedList

No need for capacity expansion; space efficiency is high.

Insertion and removal operations are fast.

Disadvantages of LinkedList

Random access (get by index) is slower because it requires traversal.

Update and search operations are less efficient compared to ArrayList.

Overall, LinkedList is suitable when frequent insertions and deletions are required, while ArrayList excels at random access and iteration performance.

JavaJDKCollectionsdata structuresLinkedList
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.