Core Java

Java Printing Stack Values Example

Printing the contents of a stack in Java is a common requirement when debugging or displaying the current state of the stack. While Java provides multiple ways to iterate and print stack elements, each has its advantages, particularly around maintaining the LIFO (Last In First Out) behavior. Let us delve into understanding Java printing stack values in detail.

1. Introduction

In Java, the Stack class resides in the java.util package and is a subclass of Vector. It represents a classic Last-In-First-Out (LIFO) stack of objects. This means that the last element pushed onto the stack is the first to be popped off.

The Stack class provides the following primary operations to work with stack elements:

  • push(E item) – Inserts the specified element onto the top of the stack.
  • pop() – Removes and returns the element at the top of the stack. Throws EmptyStackException if the stack is empty.
  • peek() – Looks at the object at the top of the stack without removing it from the stack.
  • empty() – Tests if the stack is empty. Returns true if the stack contains no items.
  • search(Object o) – Returns the 1-based position from the top of the stack where the object is located; returns -1 if not found.

The Stack class can store any type of object (due to Java generics), making it flexible for various use cases. However, it is considered a legacy class. It is generally recommended to replace LinkedList implementations with Deque implementations, such as ArrayDeque, when possible, as they offer better performance and are part of the Java Collections Framework.

Typical use cases of a stack include:

  • Parsing expressions (e.g., converting infix to postfix)
  • Undo functionality in editors
  • Backtracking algorithms (like maze solving)
  • Depth-First Search (DFS) in graph traversal

The simplicity and utility of the Stack class make it a foundational structure to understand while learning Java or data structures in general.

2. Code Example Using Various Approaches

In Java, printing stack values can be achieved using several different techniques, each with its advantages depending on the desired traversal order or programming style. The example below demonstrates how to push elements onto a Stack<String> and then explores multiple ways to retrieve and print these values.

// File: StackPrintingDemo.java
import java.util.*;

public class StackPrintingDemo {

    public static void main(String[] args) {
        Stack<String> stack = new Stack<>();
        stack.push("Apple");
        stack.push("Banana");
        stack.push("Cherry");
        stack.push("Date");

        System.out.println("1. Using toString():");
        System.out.println(stack);  // Prints in [bottom, ..., top] format

        System.out.println("\n2. Using Enhanced for-loop:");
        for (String item : stack) {
            System.out.println(item);
        }

        System.out.println("\n3. Using forEach() and lambda:");
        stack.forEach(item -> System.out.println(item));

        System.out.println("\n4. Using Iterator:");
        Iterator<String> iterator = stack.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }

        System.out.println("\n5. Using ListIterator (LIFO order):");
        ListIterator<String> listIterator = stack.listIterator(stack.size());
        while (listIterator.hasPrevious()) {
            System.out.println(listIterator.previous());
        }

        System.out.println("\n6. Using Deque:");
        Deque<String> deque = new ArrayDeque<>(stack);
        while (!deque.isEmpty()) {
            System.out.println(deque.pollLast());  // Maintains LIFO
        }
    }
}

2.1 Code Explanation

The given Java program demonstrates multiple ways to print stack values using the java.util package. It begins by creating a Stack<String> named stack and pushing four elements: “Apple”, “Banana”, “Cherry”, and “Date” onto it. First, it uses the toString() method which prints the entire stack in the default [bottom, ..., top] format. Then, it demonstrates printing using an enhanced for-loop, which iterates from the bottom to the top of the stack. Next, it uses the forEach() method with a lambda expression to print each element in the same order. The Iterator approach follows, again iterating from bottom to top. To print elements in actual Last-In-First-Out (LIFO) order, the program uses a ListIterator initialized at the end of the stack and iterates backward using hasPrevious() and previous(). Lastly, it demonstrates how a Deque (specifically, ArrayDeque) can be used to simulate LIFO by continuously polling the last element using pollLast() until the deque is empty. Each method provides a different perspective on traversing or accessing the contents of a stack in Java, ranging from traditional iteration to more functional approaches.

2.2 Code Output

The output below showcases how each of the stack traversal techniques behaves when executed. While most approaches like the enhanced for-loop, forEach(), and Iterator display the stack elements from bottom to top (i.e., in the order they were pushed), the ListIterator and Deque approaches reveal the actual Last-In-First-Out (LIFO) nature of a stack.

1. Using toString():
[Apple, Banana, Cherry, Date]

2. Using Enhanced for-loop:
Apple
Banana
Cherry
Date

3. Using forEach() and lambda:
Apple
Banana
Cherry
Date

4. Using Iterator:
Apple
Banana
Cherry
Date

5. Using ListIterator (LIFO order):
Date
Cherry
Banana
Apple

6. Using Deque:
Date
Cherry
Banana
Apple

3. Comparison Table

The table below compares various approaches to printing the contents of a Java Stack, based on whether they preserve LIFO order, their simplicity, and mutability.

ApproachMaintains LIFO?Code SimplicityMutable?Additional Notes
toString()NoVery SimpleNoUses default Stack representation, does not ensure LIFO order.
Enhanced for-loopNoSimpleNoTraverses from bottom to top, violating LIFO. Good for basic read-only iteration.
forEach() loopNoSimpleNoLambda-based, functional style. Does not respect LIFO order.
IteratorNoModerateYes (remove possible)Forward-only traversal. Allows safe element removal during iteration.
ListIterator (reverse)YesModerateYesAllows reverse traversal preserving LIFO. Useful for full control.
Deque (pollLast)YesModerateYesMimics stack behavior effectively. LIFO guaranteed with pollLast().

4. Conclusion

Java offers multiple ways to print stack values depending on your specific requirements. If you’re looking to preserve the natural LIFO order, approaches like ListIterator (in reverse) or converting to a Deque and using pollLast() are ideal. For simple inspections, toString() or a basic forEach loop is sufficient. Understanding these differences helps in writing clean and intention-revealing code, especially when dealing with stack data structures in Java.

Yatin Batra

An experience full-stack engineer well versed with Core Java, Spring/Springboot, MVC, Security, AOP, Frontend (Angular & React), and cloud technologies (such as AWS, GCP, Jenkins, Docker, K8).
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button