

Just as old as Java itself is the java.util.Stack
class, available since version 1.0, implementing the abstract data type "stack".
Stack
inherits from java.util.Vector
and, therefore, implements numerous interfaces of the Java Collections Framework. The following diagram shows the class hierarchy:

Java Stack Methods
Stack
extends Vector
with the following methods:
push()
– places an element on the stackpop()
– takes the top element from the stackpeek()
– returns the top element of the stack without removing it from the stackempty()
– checks if the stack is empty; sinceStack
already inherits theisEmpty()
method fromVector
, theempty()
method is redundant; why the JDK developers included it is a mystery to me.search()
– searches for an element on the stack and returns its distance to the top of the stack
I show how the methods work in the following example.
Just like Vector
, Stack
is thread-safe: all methods are synchronized.
Java Stack Example
The following code snippets show an example use of Stack
(you can find the complete code in the JavaStackDemo class in the GitHub repo).
First, we create a stack and put the elements "apple", "orange", and "pear" on the stack using push()
:
Stack<String> stack = new Stack<>();
stack.push("apple");
stack.push("orange");
stack.push("pear");
Code language: Java (java)
After that, we print the stack's contents – and the results of peek()
and empty()
– to the console:
System.out.println("stack = " + stack);
System.out.println("stack.peek() = " + stack.peek());
System.out.println("stack.empty() = " + stack.empty());
Code language: Java (java)
The output looks like this:
stack = [apple, orange, pear]
stack.peek() = pear
stack.empty() = false
Code language: plaintext (plaintext)
So Stack
's toString()
method prints the elements from bottom to top. The last inserted element, "pear", is at the top of the stack.
Using search()
, we can look for an element:
System.out.println("stack.search(\"apple\") = " + stack.search("apple"));
Code language: Java (java)
The output is:
stack.search("apple") = 3
Code language: plaintext (plaintext)
This means that "apple" is in the third position of the stack. That's because we pushed two more elements onto the stack after "apple".
We take out the three elements again:
System.out.println("stack.pop() = " + stack.pop());
System.out.println("stack.pop() = " + stack.pop());
System.out.println("stack.pop() = " + stack.pop());
Code language: Java (java)
We see that the elements are retrieved in reverse order:
stack.pop() = pear
stack.pop() = orange
stack.pop() = apple
Code language: plaintext (plaintext)
What happens if we call pop()
one more time?
System.out.println("stack.pop() = " + stack.pop());
Code language: Java (java)
As the stack is now empty, an EmptyStackException
is thrown:
Exception in thread "main" java.util.EmptyStackException
at java.base/java.util.Stack.peek(Stack.java:101)
at java.base/java.util.Stack.pop(Stack.java:83)
at eu.happycoders.demos.stack.JavaStackDemo.main(JavaStackDemo.java:28)
Code language: plaintext (plaintext)
Just like pop()
, also peek()
would throw an EmptyStackException
if the stack is empty.
Why You Should Not Use Stack (Anymore)
The Java developers recommend not to use java.util.Stack
anymore. The Javadoc states:
"A more complete and consistent set of LIFO stack operations is provided by the Deque interface and its implementations, which should be used in preference to this class."
What exactly does this mean? In my opinion, Stack
should not be used for the following reasons:
- By extending
Vector
,Stack
provides operations that have no place in a stack, such as accessing elements by their index or inserting and deleting elements at arbitrary positions. Stack
does not implement an interface. So by usingStack
, you are committing to a specific implementation.- Using
synchronized
on every method call is not a particularly performant means of making a data structure thread-safe. Better is usually optimistic locking by CAS ("compare-and-swap") operations as found in the concurrent queue and deque implementations.
Stack Alternatives
Instead, the Java developers recommend using one of the Deque implementations, such as ArrayDeque.
The java.util.Deque interface is similar to that of Stack
:
- We have the methods
push()
,pop()
, andpeek()
. - Instead of
empty()
, you have to callisEmpty()
. - There is no
search()
method.
The following code (ArrayDequeDemo in the GitHub repo) shows the exemplary application of ArrayDeque
as a stack:
public class ArrayDequeDemo {
public static void main(String[] args) {
Deque<String> stack = new ArrayDeque<>();
stack.push("apple");
stack.push("orange");
stack.push("pear");
System.out.println("stack = " + stack);
System.out.println("stack.peek() = " + stack.peek());
System.out.println("stack.isEmpty() = " + stack.isEmpty());
System.out.println("stack.pop() = " + stack.pop());
System.out.println("stack.pop() = " + stack.pop());
System.out.println("stack.pop() = " + stack.pop());
System.out.println("stack.pop() = " + stack.pop());
}
}
Code language: Java (java)
As you can see, the code is almost identical to the previous example.
However, keep in mind that deques also provide operations that a stack should not offer, such as inserting and removing elements at the bottom of the stack.
Alternatively, you can implement your own stack class.
In the following parts of this tutorial, I will present various stack implementations:
- using an ArrayDeque
- using an Array
- using a LinkedList
- using Queues
If you still have questions, please ask them via the comment function. Do you want to be informed about new tutorials and articles? Then click here to sign up for the HappyCoders.eu newsletter.