As we know that stack is a data structure which follows LIFO order. And as per my knowledge stack allows to access top element only. But in Java we can use iterator with stack which somehow contradict the above idea of allowing access to only top element.
Sample code
Stack<Integer> s=new Stack<Integer>();
s.push(10);
s.push(20);
s.push(30);
------------------------------------------------------------------------
Iterator<Integer> itr=s.iterator();
while(itr.hasNext())
{
System.out.print(itr.next() + " "); // ouput:- 10 20 30
}
Now I have an iterator on stack which can traverse the stack in FIFO order and I can even delete any element by using itr.remove()
It's very confusing :)
Please explain...
PS: In case I use listIterator at the place of iterator then it's even more confusing because former one provides more methods.
Java Stack<T> provides more operations than the abstract stack data type. Most likely, this is done for historical reasons, because Stack has been part of Java 1.0, and its designers decided to derive it from Vector. This is how operations from Vector became operations on Stack. Once you allow additional public operations to a public class, there is no way to take them back.
This does not mean, however, that the class is somehow broken: if you do not want the additional operations provided by Vector<T>, do not use them in your code.
Related
As we know in Java each class that implements Collection interface should implement Iterator<E> iterator() method.
Stack and Queue are parts of collection hierarchy and implement this method as well. So we can write something like this:
Stack stack = new Stack();
// Deque stack = new ArrayDeque<>();
stack.add( "1" );
stack.add( "2" );
stack.add( "3" );
Iterator i = stack.iterator();
while ( i.hasNext() ) {
Object o = i.next();
if ( o.equals( "2" ) ) {
i.remove();
}
}
My concerns here are:
Is it ok that we are able to delete elements from the middle of the stack/queue?
Is it ok that stack/queue should "show" only one element (last in stack and first in queue) but actually we are able to get all of them without calling "pop","enqueue" methods?
In the strictest sense, Stack and Queue should not allow iteration over it's element but the only reason this restriction exists is to justify the existence of these data structures. As per sgi
Stack does not allow iteration through its elements.
This restriction is the only reason for stack to exist at all. Note that any Front Insertion Sequence or Back Insertion Sequence can be used as a stack; in the case of vector, for example, the stack operations are the member functions back, push_back, and pop_back. The only reason to use the container adaptor stack instead is to make it clear that you are performing only stack operations, and no other operations.
While some implementations follow this, for example std::stack in C++ does not expose iterator, other implementation provide iterators as a feature. Stack in java is built on top of Vector which implements iterator. Queue is built on top of Collection which requires iterator to be implemented. To answer your questions
Is it ok that we are able to delete elements from the middle of the stack/queue?
Yes. The underlying implementation will make sure that your stack/queue is in a consistent state after the deletion.
Is it ok that stack/queue should "show" only one element (last in stack and first in queue) but actually we are able to get all of them without calling "pop","enqueue" methods?
Yes it's a feature of the underlying implementation.
Is it ok that we are able to delete elements from the middle of the
stack/queue?
Yes since stack/queue both will keep their contract even after deleting , after all the methods exposed by stack/queue manipulate the internal implementation which is used for the deletion
Is it ok that stack/queue should "show" only one element (last in
stack and first in queue) but actually we are able to get all of them
without calling "pop","enqueu" methods?
Yes you are not violating either contract since the remove is done throw iterator interface of the element not queue or stack
I notice that linkedList has some methods like pop and push. Typically, if I want to use the feature of stack (FILO).Would the linkedList be the best choice?
LinkedList will work, and in fact implements the most stack-like interface in the JDK, Deque.
ArrayDeque is the other main non-threadsafe implementation, and is probably more efficient if you only need the stack operations. The above link for Deque lists the other two JDK-provided implementations, which are thread safe.
There is no better or worse approach to implement a stack but they have different advantages.
Implementation based on linked list gives you more flexibility over the container's capacity since you can theoretically always add more elements to it. Array based stack is more limited in terms of capacity. Linked list implicate more space overhead though, as you need to store references to other nodes.
Performance wise with a stack you only access the top element which means you don't need the random access feature that an array gives you over linked lists.
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<Integer> stack = new ArrayDeque<Integer>();
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> 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
I recently read a book "The Java Tutorials" 3rd edition.
It talks about inner class implementation as the picture shows.
In the 3rd paragraph, it says "The Stack class itself should not implement the Iterator interface, because...".
I cannot find any reason that Stack class should not implement Iterator. The reason given is NOT persvasive.
Could you explain it?
Fundamentally, an iterator is stateful - it needs to know where it's pointing within the collection. That doesn't belong as part of the collection itself - and the explanation given is the right one... it's entirely possible to have two independent iterator objects, iterating over the same collection object. How would you model that if the collection itself implemented the Iterator interface? It's possible (e.g. creating a new instance of the collection which in turn held a reference to the original collection), but it would be really ugly.
There are separate concerns here:
The collection of data
A cursor positioned within the collection
Separate concerns => separate classes.
The simplest way of persuading yourself of this is probably to try to implement your own collection though - and then have multiple iterators. For example, you might want to try:
List<String> foo = new MyListImplementation<String>();
foo.add("a");
foo.add("b");
// The enhanced for loop uses Iterable/Iterator for non-arrays
for (String x : foo) {
for (String y : foo) {
System.out.println(x + " " + y);
}
}
That should print out:
a a
a b
b a
b b
Try implementing it without having two classes, and see how you do, bearing separation of concerns in mind.
The stack should not implement Iterator itself because then you could have only one iterator at a time, and iterating over a stack would change the stack.
For the latter issue, notice that the nested class has a "currentItem" field. This field would need to be in "Stack", and would change when next() is called. Iterating over a collection should not change the collection.
The first problem is more serious: suppose two people iterate over the stack (or one method wishes to create two iterators over the stack). Then if iterator() returned this, the two iterators would be the same thing. Calling next() on one would move the other. Chaos.
A Stack cannot be its own Iterator because a Stack supports more than one Iterator.
You might want to iterate over the Stack more than once. These iterations might occur at different times, or even the same time. Multiple iterations at the same time clearly require multiple objects. Multiple iterations at different times require multiple objects because the Iterator interface does not support returning to the start.
There are 2 reasons I can think of off the top of my head.
Multiple types of iterators
You may want multiple types of iterators that iterate in different ways. For instance, both a Forward Iterator and a Backward Iterator (iterates from end of the container to beginning).
Multiple instances of iterators
If you have a multiple pass algorithm and/or nested loops, each loop may want its own iterator that keeps track of where it is in the container independent of the other iterators.
It would be difficult if not impossible to support these functionalities with the Iterator interface implemented in the Stack class.
Just to add to the discussion, the inner class will have access to private data of the Stack class, so in this way, the Stack class will manage to handle the client programmer an object, or multiple objects(the iterator(s), and still these object will be able to access the class and to provide separate iteration over the collection.
I just noticed that Stack extends Vector in Java, ref: here.
Vector is slower than ArrayList so is there a better Stack I can use?
Thanks.
java.util.ArrayDeque has all stack methods (pop, push, peek) and it is fast. API This class is likely to be faster than Stack when used as a stack, and faster than LinkedList when used as a queue.
You can use Apache's ArrayStack that is based on ArrayList instead of Vector:
http://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections/ArrayStack.html
I find that LinkedList does a good job when you only need to access the front (and back) of a data structure. It adds with complexity O(1) and gets from the front also with O(1). It also never has to worry about resizing the backing array.