I have a method which generates an object each time I execute it, and I need to reverse the order with which I am getting them. So I thought the natural way to do it would be a Stack, since it is LIFO.
However, the Java Stack does not seem to play well with the new Java 8 streaming API.
If I do this:
Stack<String> stack = new Stack<String>();
stack.push("A");
stack.push("B");
stack.push("C");
List<String> list = stack.stream().collect(Collectors.toList());
System.out.println("Collected: " + list);
The output I get is:
Collected: [A, B, C]
Why isn't it outputing them in the expected LIFO order to the stream?
Is this the right way to flush out all the items from the stack to a list in the right (LIFO) order?
As already mentioned in the comments, we have well tested Deque
interface which should be preferred.
But I will you give the reason why Stack
shouldn't be used.
At first, the Java Doc. of the Stack says itself:
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. For example:
Deque stack = new ArrayDeque();
See JavaDoc.
So what it is the problem with the Stack
class.
Like Martin Fowler already mentioned in his book
Refactoring: Improving the Design of Existing Code
at the refactoring method Replace Inheritance with Delegation,
a Stack shouldn't inherit from a Vector.
One of the classic examples of inappropriate inheritance is making a
stack a subclass of vector. Java 1.1 does this in its utilities
(naughty boys!)
[6, p. 288]
Instead, they should have used delegation like in the picture below,
which is also from the book.
See also here: Replace Inheritance with Delegation
So but why is this a problem:
Because the Stack has only 5 Methods:
- pop
- push
- isEmpty
- search
size
size()
and isEmpty()
are inherited from the Vector
class and the other methods from the Vector
are not used. But through the inheritance, other methods are forwarded to the Stack
class which makes no sense.
And Fowler says to this problem:
You can live with the situation and use convention to say that
although it is a subclass, it's using only part of the superclass
function. But that results in code that says one thing when your
intention is something else—a confusion you should remove.
This hurts the Interface Segregation Principle
which says:
CLIENTS SHOULD NOT BE FORCED TO DEPEND UPON INTERFACES THAT THEY DO
NOT USE.
You can check out the source code of the Vector and Stack class
and you will see that the Stack class inherit the spliterator
method
and the VectorSpliterator
innerClass from the Vector
class.
This method is used by the Collection
interface to impl. the default version of stream method:
default Stream<E> More ...stream() {
return StreamSupport.stream(spliterator(), false);
}
So avoid simply the usage of the Vector
and Stack
class.
[6] Refactoring: Improving the Design of Existing Code Fowler, Martin
year 1997