Java LinkedList peek() - Inspect First Element Without Removal
java linkedlist peek: Learn how to use Java LinkedList peek() to inspect the first element without removing it, and understand its behavior on empty lists and differen...
java linkedlist peek requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.
When you need to inspect the first element of a LinkedList without removing it, the peek() method is the direct answer. In Java, LinkedList implements both Queue and Deque, so it provides several peek variants. Understanding which one to use and how they behave on empty lists prevents subtle bugs in your queue and deque logic.
What peek() Returns
The peek() method returns the head (first element) of the list, or null if the list is empty. It does not remove the element. This is part of the Queue interface. For a LinkedList, the head is the first element in the list.
LinkedList<String> tasks = new LinkedList<>(); tasks.add("compile"); tasks.add("test"); tasks.add("deploy"); String next = tasks.peek(); System.out.println(next); // prints "compile" System.out.println(tasks.size()); // still 3
The method signature is E peek() where E is the element type. It is equivalent to peekFirst() for a LinkedList, but peek() is the standard Queue operation.
peekFirst() and peekLast()
LinkedList also implements Deque, which adds peekFirst() and peekLast(). These methods are more explicit about which end you are inspecting. peekFirst() behaves exactly like peek(), returning the first element or null if empty. peekLast() returns the last element or null.
LinkedList<Integer> numbers = new LinkedList<>(); numbers.add(10); numbers.add(20); numbers.add(30); System.out.println(numbers.peekFirst()); // 10 System.out.println(numbers.peekLast()); // 30
Use peekFirst() and peekLast() when your code uses the list as a deque and you want to avoid ambiguity about which end is being accessed. For queue-style processing, peek() is idiomatic.
Behavior on an Empty LinkedList
All three peek methods return null when the list is empty. They do not throw an exception. This is different from getFirst() and getLast(), which throw NoSuchElementException if the list is empty.
LinkedList<String> empty = new LinkedList<>(); String value = empty.peek(); // null String first = empty.peekFirst(); // null String last = empty.peekLast(); // null
This makes peek() safe to call without checking isEmpty() first, as long as your logic handles a null return value. If null is a valid element in your list, you need another way to distinguish an empty list from a list containing null. In that case, check isEmpty() before peeking.
peek() vs poll()
poll() also returns the head of the list, but it removes the element. peek() leaves the list unchanged. This is the key difference between inspecting and consuming an element.
LinkedList<String> queue = new LinkedList<>(); queue.add("first"); queue.add("second"); String head = queue.peek(); // "first" System.out.println(queue.size()); // 2 String consumed = queue.poll(); // "first" System.out.println(queue.size()); // 1
Use peek() when you need to look at the next item without committing to processing it yet. Use poll() when you are ready to remove and process it. This pattern is common in task schedulers and request queues.
Performance Considerations
peek(), peekFirst(), and peekLast() all run in constant time, O(1), for a LinkedList. The list maintains references to both the first and last nodes, so accessing either end does not require traversal. This is true regardless of the list size. The same applies to poll() and getFirst().
The constant-time behavior is one reason LinkedList is often used as a queue or deque implementation. However, accessing an element by index is O(n), so peek() is the efficient way to inspect the ends.
Practical Example: Using peek() in a Work Queue
Consider a simple work queue where you want to inspect the next task before deciding whether to process it immediately or defer it.
LinkedList<Runnable> pendingTasks = new LinkedList<>(); // Add some tasks pendingTasks.add(() -> System.out.println("Task 1")); pendingTasks.add(() -> System.out.println("Task 2")); while (!pendingTasks.isEmpty()) { Runnable next = pendingTasks.peek(); if (next != null) { // Decide to process now next.run(); pendingTasks.poll(); // remove after processing } }
In this example, peek() lets you see the next task without removing it, so you can make a decision based on its identity or state. The poll() call then removes it after it has been processed. This pattern avoids the risk of losing a task if an exception occurs between peeking and polling.
Common Mistakes and Edge Cases
One common mistake is using getFirst() when you want a non-throwing peek. getFirst() throws NoSuchElementException on an empty list, which can crash your program if you don't catch it. Prefer peek() when you want a null return.
Another edge case is storing null elements in the list. Since peek() returns null for both an empty list and a list whose head is null, you must check isEmpty() to differentiate. This is rarely an issue because most queue use cases avoid null elements, but it is worth knowing.
Also, remember that LinkedList is not thread-safe. If multiple threads access the same list, you need external synchronization or a concurrent collection like ConcurrentLinkedDeque. The peek methods themselves are not atomic operations in a multi-threaded context.