Sentinel Nodes

Solution

The guards exist wherever a real neighbor is missing: the first node has no predecessor and the last has no successor, so dereferencing target.prev.next or target.next.prev there throws a NullPointerException. Every node in the interior has a real node on both sides, so the two unguarded rewiring lines already work there without needing a check.

Solution

The sentinels hold no list value: their value field is never a real element, and they are never handed to the caller. Their only job is to give every real node a non-null neighbor on both sides. With them in place, target.prev and target.next are never null for a real node, so the two rewiring lines from the interior case work unconditionally, and the two guard ifs can be deleted.

Solution

The list is empty when head.next == tail (equivalently tail.prev == head), not when head == null. The first real value is head.next, not head itself, since head is the front sentinel.