Java LinkedList addFirst: Usage and Performance
java linkedlist addfirst: Learn how to use Java LinkedList addFirst to prepend elements efficiently, understand its O(1) performance, and see when to choose it over ot...
java linkedlist addfirst requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.
When you need to prepend an element to a Java LinkedList, the addFirst method is the direct way to do it. It adds the element at the head of the list, shifting the previous head to the second position. This operation is fundamental to linked list structures and is part of the Deque interface that LinkedList implements. In this article, we'll examine how addFirst behaves, its performance characteristics, and the practical decisions you need to make when using it.
What addFirst Does
The addFirst(E e) method inserts the specified element at the front of the list. It is equivalent to add(0, e) but is more explicit and avoids the overhead of index-based insertion logic. The method returns void, unlike offerFirst which returns a boolean to indicate success. Since LinkedList allows null elements, addFirst(null) is valid and will insert a null reference at the head.
LinkedList<String> list = new LinkedList<>(); list.addFirst("first"); list.addFirst("new head"); System.out.println(list); // [new head, first]
After the second call, the list contains new head at index 0 and first at index 1. The order of elements reflects the sequence of insertions at the head.
How addFirst Works Internally
LinkedList is a doubly-linked list. Each node holds a reference to the previous node, the next node, and the element itself. The list maintains references to the first node (first) and the last node (last). When you call addFirst, a new node is created and linked to the current first node. The new node's next pointer is set to the old first node, and the old first node's previous pointer is set to the new node. The first reference is then updated to the new node.
This operation does not depend on the size of the list. It always involves creating one node and updating a constant number of references. Therefore, its time complexity is O(1). This is a key advantage over ArrayList, where inserting at the beginning requires shifting all existing elements to the right, an O(n) operation.
Using addFirst in Code
addFirst is useful when you need to maintain a stack-like behavior where the most recently added element is always processed first. For example, an undo history could use addFirst to keep the latest action at the front.
LinkedList<String> undoHistory = new LinkedList<>(); undoHistory.addFirst("Open file"); undoHistory.addFirst("Edit line 3"); undoHistory.addFirst("Save file"); // The most recent action is at index 0 String lastAction = undoHistory.getFirst();
Because LinkedList implements Deque, you can also use push() which is equivalent to addFirst. The choice between them is stylistic; push is more conventional when using the list as a stack.
LinkedList<Integer> stack = new LinkedList<>(); stack.push(10); stack.push(20); int top = stack.pop(); // returns 20
addFirst vs addLast vs add
The add method, when called without an index, appends to the end of the list, which is equivalent to addLast. The table below compares the three insertion methods.
| Method | Position | Time Complexity | Return Value |
|---|---|---|---|
addFirst | Head | O(1) | void |
addLast | Tail | O(1) | void |
add(index) | Specified index | O(n) | void |
addFirst and addLast are both O(1) because they only update the boundary nodes. add(index) must traverse the list to find the insertion point, making it O(n) in the worst case. If you are frequently inserting at both ends, LinkedList is a strong candidate. If you need random access by index, ArrayList is better despite its O(n) insertion at the head.
Performance and Memory Considerations
While addFirst is O(1), each node in a LinkedList carries two extra references compared to an array. This memory overhead is significant for large lists. Additionally, LinkedList has poor cache locality because nodes are scattered in memory, which can degrade performance when iterating. In contrast, ArrayList stores elements contiguously, enabling faster iteration and random access.
For operations that only prepend elements, ArrayDeque is often a better choice than LinkedList. ArrayDeque also provides addFirst with O(1) amortized time and uses a resizable array, which has lower memory overhead and better cache behavior. However, ArrayDeque does not allow null elements, so if you need to store nulls, LinkedList is necessary.
Common Pitfalls and Edge Cases
One common mistake is assuming addFirst returns a boolean like offerFirst. It does not; it returns void. If you need to check whether the element was accepted (which only matters for capacity-restricted queues), use offerFirst instead.
Another edge case is inserting into an empty list. addFirst on an empty list works correctly and sets both first and last to the new node. There is no special handling required.
Null elements are allowed. If your application relies on null to represent an absence of value, addFirst(null) will work. But be cautious when using getFirst() later, as it will return null, which could be ambiguous if null is also used as a sentinel.
When to Choose LinkedList.addFirst
Use LinkedList.addFirst when you need a doubly-linked list with constant-time insertion at the head, and when you also require the ability to insert at the tail or remove from either end. It is appropriate for implementing queues, stacks, or deques where null elements must be supported. If you only need a stack or queue and nulls are not required, prefer ArrayDeque for better performance and memory usage. If your primary need is random access, ArrayList is the right choice, even though prepending is O(n). The decision ultimately depends on the balance between insertion flexibility and access patterns in your specific use case.
When building a list where the most frequent operation is prepending and you do not need index-based access, LinkedList.addFirst provides a straightforward O(1) solution. Its main tradeoff is memory overhead and reduced cache efficiency, which becomes more pronounced as the list grows. For small lists, the difference is negligible; for large lists, measure and profile to confirm the behavior meets your performance requirements.