Solution: Fields and Constructor

Before we write any operations, we need to decide what fields the list has.

In the version from the chapter, head points at the first real node and tail points at the last real node. In the sentinel version, head and tail point at sentinel nodes instead:

          ┌─────┐      ┌─────┐
head ───▶ │ ░░░ │ ◀──▶ │ ░░░ │ ◀─── tail
          └─────┘      └─────┘
           front        back
         sentinel     sentinel
Solution

The state is still head, tail, and size, but head and tail now refer to sentinel nodes:

public class LinkedList<T> {

  private Node<T> head;  // front sentinel
  private Node<T> tail;  // back sentinel
  private int size;  // number of real nodes

  private static class Node<T> {
    T value;
    Node<T> next;
    Node<T> prev;

    Node(T value) {
      this.value = value;
    }
  }

  public LinkedList() {
    head = new Node<>(null);
    tail = new Node<>(null);
    head.next = tail;
    tail.prev = head;
    size = 0;
  }

  public int size() {
    return size;
  }
}

The sentinels hold null, but that null is not a list value. The real values are always between head and tail, and size counts only those real nodes.