Stack
About
Stack is a part of the Java Collections Framework and is a subclass of Vector. It represents a last-in, first-out (LIFO) stack of objects. It allows elements to be added, removed, and retrieved in a way that the most recently added element is always the first to be removed.
The Stack class provides methods that operate on the stack in a LIFO manner, such as push(), pop(), peek(), and empty().
Features
LIFO (Last In, First Out): The last element added is the first one to be removed.
Dynamic Size: Similar to
ArrayList,Stackresizes dynamically as elements are added or removed.Allowing Duplicates: Like
ArrayList,Stackallows duplicates.Resizes Automatically: The size of the stack grows or shrinks automatically based on the number of elements.
Thread-Safe (but not recommended):
Stackis synchronized, meaning it is thread-safe for concurrent use.Element Access via
peek(): Allows looking at the top element of the stack without removing it.Inheritance:
Stackis a subclass ofVector, so it inherits the functionality of a resizable array.Empty Check via
empty(): Provides an easy way to check if the stack is empty.Accessing Element via
search(): Can search for an element in the stack and return its distance from the top of the stack.
Key Methods
push(E item): Adds an item to the top of the stack.pop(): Removes and returns the item at the top of the stack. ThrowsEmptyStackExceptionif the stack is empty.peek(): Returns the item at the top of the stack without removing it. ThrowsEmptyStackExceptionif the stack is empty.firstElement(): Returns the item at the bottom of the stack without removing it. ThrowsEmptyStackExceptionif the stack is empty.empty(): Returnstrueif the stack is empty, otherwisefalse.search(Object o): Returns the 1-based position of the object in the stack, or -1 if not found.size(): Returns the number of elements in the stack.clear(): Removes all elements from the stack (not directly available, but can be done usingremoveAllElements()from the parentVectorclass).clone(): Creates a shallow copy of the stack.contains(Object o): Returnstrueif the stack contains the specified element.
Big O Time Complexity for Stack Operations
Operation
Big(O) Time Complexity
Details
Push (add an element)
O(1)
Adding an element to the top of the stack takes constant time.
Pop (remove an element)
O(1)
Removing the top element from the stack takes constant time.
Peek (top element)
O(1)
Accessing the top element without removal takes constant time.
Empty Check
O(1)
Checking if the stack is empty is constant time.
Search
O(n)
Searching through the stack requires iterating over the elements.
Size
O(1)
Retrieving the size of the stack is constant time.
Contains
O(n)
Checking if an element exists in the stack requires a scan through all elements.
Example
Basic Operation
Generic Stack
We can create a stack for any data type, ensuring type safety.
Custom Class in Stack
We can store custom objects in the stack.
Thread-Safety in Stack (Not Recommended)
Since Stack is synchronized i.e. each individual method call, such as push() or pop(), is thread-safe on its own., it can be used in a multithreaded environment, but modern alternatives like Deque are preferred for performance reasons.
Even though Stack methods are synchronized, method-level synchronization alone does not guarantee thread safety for compound operations or sequences of method calls. For example:
Compound Operations: If we need to perform multiple operations atomically (as a single unit of work), method-level synchronization is not sufficient.
Example:
Here, another thread could modify the stack between the
isEmpty()andpop()calls, leading to incorrect behavior or exceptions.
Manual Synchronization Block: By synchronizing on the entire
Stackobject, we can ensure that the entire sequence of operations is performed atomically:In this example, the
isEmpty()check andpop()are both protected within the same synchronization block.
Why Stack is Not Recommended in Modern java?
In modern Java development, Stack is generally not recommended due to several reasons. These are related to its design, inefficiencies, and better alternatives that have emerged in the Java Collections Framework.
1. Legacy Design
Stackis a part of the legacy collections (introduced in JDK 1.0) and extendsVector, another legacy class.Vectoris synchronized, which makesStacksynchronized by inheritance. This synchronization is often unnecessary and can lead to performance bottlenecks.
2. Synchronized by Default
The synchronization in
Stackis not fine-grained or optional. This makes it slower compared to alternatives likeArrayDequewhen synchronization is not required.Modern Java provides thread-safe data structures like
ConcurrentLinkedDequeorLinkedBlockingDeque, which are more efficient for concurrent environments.
3. Inefficient for Stack Operations
Stackinherits many irrelevant methods fromVector, likeinsertElementAt, which don't align with the stack principle of Last-In-First-Out (LIFO).These methods clutter the API and make it less intuitive for stack-specific operations.
Modern alternatives like
ArrayDequeare specifically designed for stack and queue operations.
4. Better Alternatives
ArrayDeque: This is the recommended class for stack operations in modern Java. It is faster, more memory-efficient, and does not have the unnecessary overhead of synchronization unless explicitly needed.
LinkedList: It also implements theDequeinterface and can be used for stack-like operations, thoughArrayDequeis preferred for performance reasons.
5. Poor Memory and Performance Management
The resizing mechanism of
Vector(and thusStack) is not as optimized as modern implementations.Modern classes like
ArrayDequeuse an adaptive resizing strategy that is more efficient for growing and shrinking the stack.
6. Lack of Modern Features
Stackdoes not support features like lambdas, streams, or functional programming constructs seamlessly, which are common in modern Java practices.
When to Use Stack ?
Expression Evaluation: Useful in evaluating postfix or prefix expressions.
Undo Mechanism: Often used in undo operations (LIFO order).
Backtracking Algorithms: Useful in problems such as maze solvers or recursive algorithms.
Browser History Navigation: Browsers use stacks to store previous pages to support the "Back" button functionality.
Last updated