45

Today I was trying to push in java.util.Stack class and then use the Iterator to iterate (without using pop) through the items. I was expecting LIFO property but got surprised.

Here is the code that I was trying.

import java.util.*;
import java.util.Stack;

public class Main {
    public static void main(String[] args) {
        RobStack<Integer> rstack = new RobStack<Integer>(); // Correct Implementation
        Stack<Integer> jstack = new Stack<Integer>(); // Default Java Implementation
        rstack.push(0); jstack.push(0);
        rstack.push(1); jstack.push(1);
        rstack.push(2); jstack.push(2);
        rstack.push(3); jstack.push(3);

        System.out.print("Algo Stack: ");
        for (int i : rstack)
            System.out.print(i + " ");
        System.out.print("\nJava Stack: ");
        for (int i : jstack)
            System.out.print(i + " ");
    }

}

The output the above program is given below:

Algo Stack: 3 2 1 0 
Java Stack: 0 1 2 3 

In the above code jstack uses the default Java implementation and rstack uses the implementation provided by Robert Sedgewick for his Algorithm class. I found that Prof. Robert's implementation works fine but the java.util.Stack implementation fails.

Is it a bug or is it by design?

Helder Pereira
  • 5,522
  • 2
  • 35
  • 52
vincent mathew
  • 4,278
  • 3
  • 27
  • 34
  • 10
    Note: `Stack` is obsolete, you should use a `Deque` instead (for instance an `ArrayDeque` – fge Jun 07 '13 at 20:54
  • And what if you use pop() operation? – jtomaszk Jun 07 '13 at 20:57
  • 4
    In support of fge's comment, in the doc of [Stack](http://docs.oracle.com/javase/7/docs/api/java/util/Stack.html) class: `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.` – nhahtdh Jun 07 '13 at 20:58
  • see pop() Returns: The object at the top of this stack (the last item of the Vector object). the last item , so here u realize that is not the first in the structure inside, so when u iterate u should make a reverse iteration hihi, very bad design – nachokk Jun 07 '13 at 21:00

8 Answers8

34

See Bug ID 4475301 : RFE: java.util.Stack.iterator() iterates the wrong way. This behavior is by (bad) design. Java's built-in Stack iterator methods are inherited from other classes, so they don't behave as you'd expect.

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
  • 1
    Why didn't they correct the bug when it can be done by just overriding the Iterator method? – vincent mathew Jun 07 '13 at 21:04
  • 1
    @vincentmathew Yes, they could have overridden the `iterator()` method just like in Prof. Sedgewick's code that you linked to in order to make it iterate in LIFO order (assuming the same internal representation). – Bill the Lizard Jun 07 '13 at 21:07
  • 1
    @BilltheLiazard Maybe they could not have. "It was an incorrect design decision to have Stack extend Vector ("is-a" rather than "has-a"). We sympathize with the submitter but cannot fix this because of compatibility." – vincent mathew Jun 07 '13 at 21:10
  • 2
    @vincentmathew Even if they had a different internal representation for the `Stack` (which is probable; I think they use an expanding array approach), they could have come up with some `iterator()` method that iterates in the expected order. I guess iteration order isn't really a part of the design contract of a stack data structure, but it still seems like a poor choice to me. – Bill the Lizard Jun 07 '13 at 21:13
  • I know this is a very very old thread, but I just wanted to note that they could not invert the iterator, because that would break any code, which accepted a Vector if you gave that method a Stack. Which just goes to show that a Stack is not a vector, and it should not have extended Vector. – MTilsted May 13 '20 at 21:51
13

You should use Deque instead of Stack.

Deque<Integer> stack = new ArrayDeque<Integer>();

See Oracle Doc

Bashir
  • 266
  • 3
  • 10
3

Well by principle, you should not iterate over a Stack, but only push on top or pop from top. As for actual implementation, most languages, including Java, use another collection type to implement a Stack. From strict requirements point of view, it should allow constant time push, top and pop operation.

Any additional features (or bug in this case), should just be ignored and not relied upon for coding.

Shamim Hafiz - MSFT
  • 21,454
  • 43
  • 116
  • 176
2

Perhaps, you can use .get() to print items within stack from top to bottom.

Stack<Integer> stack = new Stack<Integer>();
stack.push(3);
stack.push(2);
stack.push(1);
// print from top to bottom
for(int i = stack.size() - 1; i >= 0; i--){
   System.out.println(stack.get(i));
}
/*
output
1
2
3
*/
1

Eclipse Collections includes a mutable stack implementation where the iterator returns values from top to bottom. This code prints 3, 2, then 1.

MutableStack<Integer> stack = ArrayStack.newStack();
stack.push(1);
stack.push(2);
stack.push(3);
for (Iterator<Integer> iterator = stack.iterator(); iterator.hasNext(); )
{
    Integer each = iterator.next();
    System.out.println(each);
}

MutableStack does not extend MutableCollection or Collection, so that you can't remove from the middle of the stack, for example. Methods that implement internal iteration patterns like forEach(), select(), collect(), anySatisfy(), allSatisfy(), etc. also process elements from top to bottom. This code prints the same thing.

stack.forEach(Procedures.println(System.out));

Note: I am a committer for Eclipse collections.

Donald Raab
  • 6,458
  • 2
  • 36
  • 44
Craig P. Motlin
  • 26,452
  • 17
  • 99
  • 126
1

Stack inherits .listIterator() from AbstractList which allows inverse order iteration.

Stack<Integer> stack = new Stack<Integer>();
stack.push(1);
stack.push(2);
stack.push(3);
for (ListIterator<Integer> iterator = stack.listIterator(stack.size()); iterator.hasPrevious();) {
    Integer integer = iterator.previous();
    System.out.println(integer);
}
// Output: 3 2 1
tbraun
  • 2,636
  • 31
  • 26
0

Instead of a Stack you can use a LinkedList and use the push and pop methods.

ceving
  • 21,900
  • 13
  • 104
  • 178
0

Here's a stack implementation with built-in reverse order iteration.

public class PowerStack<T> implements Iterable {
    private List<T> items = new ArrayList<T>();
    
    void push(T item) {
        items.add(item);
    }
    
    void pop() {
        this.items.remove(this.topElementIndex());
    }
    
    T top() {
        return items.get(this.topElementIndex());
    }
    
    private int topElementIndex() {
        return items.size() - 1;
    }
        
    @Override
    public Iterator<T> iterator() {
        return new ReverseOrderIterator<T>(items);
    }
}

public class ReverseOrderIterator<T> implements Iterator<T> {
    private List<T> items;
    private int index;
    
    public ReverseOrderIterator(List<T> items) {
        this.items = items;
        this.index = items.size() - 1;
    }
    
    public boolean hasNext() {
        return this.index > 0;
    }
    
    public T next() {
        return this.items.get(index--);
    }
}

Allan Juan
  • 2,048
  • 1
  • 18
  • 42