java.util.Stack 的迭代器中是不是有错误?
Posted
技术标签:
【中文标题】java.util.Stack 的迭代器中是不是有错误?【英文标题】:Is there a bug in java.util.Stack's Iterator?java.util.Stack 的迭代器中是否有错误? 【发布时间】:2013-06-04 06:31:14 【问题描述】:今天我试图推入java.util.Stack
类,然后使用Iterator
迭代(不使用pop)通过项目。我期待 LIFO 财产,但感到惊讶。
这是我正在尝试的代码。
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 + " ");
上述程序的输出如下:
Algo Stack: 3 2 1 0
Java Stack: 0 1 2 3
在上面的代码中,jstack
使用默认的 Java 实现,rstack
使用 implementation provided by Robert Sedgewick 作为他的算法类。我发现 Robert 教授的实现工作正常,但 java.util.Stack
实现失败。
这是一个错误还是设计?
【问题讨论】:
注意:Stack
已过时,您应该改用Deque
(例如ArrayDeque
如果使用pop()操作呢?
支持fge的评论,在Stack类的doc中: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.
参见 pop() 返回: 此堆栈顶部的对象(Vector 对象的最后一项)。最后一项,所以在这里你意识到这不是结构里面的第一个,所以当你迭代你应该做一个反向迭代hihi,非常糟糕的设计
【参考方案1】:
见Bug ID 4475301 : RFE: java.util.Stack.iterator() iterates the wrong way。这种行为是(不良)设计的。 Java 的内置 Stack
迭代器方法继承自其他类,因此它们的行为与您预期的不同。
【讨论】:
当可以通过覆盖 Iterator 方法来解决问题时,他们为什么不纠正错误? @vincentmathew 是的,他们可以覆盖iterator()
方法,就像您链接到的 Sedgewick 教授的代码中一样,以便使其以 LIFO 顺序迭代(假设相同的内部表示)。
@BilltheLiazard 也许他们做不到。 “让 Stack 扩展 Vector(“is-a”而不是“has-a”)是一个错误的设计决定。我们对提交者表示同情,但由于兼容性问题无法解决此问题。”
@vincentmathew 即使他们对Stack
有不同的内部表示(这很可能;我认为他们使用扩展数组方法),他们也可以想出一些iterator()
方法以预期的顺序迭代。我猜迭代顺序并不是堆栈数据结构设计契约的一部分,但对我来说它仍然是一个糟糕的选择。
我知道这是一个非常古老的线程,但我只是想指出他们不能反转迭代器,因为这会破坏任何代码,如果你给该方法一个 Stack,它接受一个 Vector .这只是表明堆栈不是向量,它不应该扩展向量。【参考方案2】:
你应该使用 Deque 而不是 Stack。
Deque<Integer> stack = new ArrayDeque<Integer>();
See Oracle Doc
【讨论】:
【参考方案3】:原则上,您不应该遍历Stack
,而只能推入顶部或从顶部弹出。至于实际实现,大多数语言,包括Java,都使用另一个collection type
来实现一个Stack
。从严格的要求来看,它应该允许恒定时间push, top and pop
操作。
任何附加功能(或本例中的错误)都应该被忽略,而不是依赖于编码。
【讨论】:
【参考方案4】:也许,您可以使用 .get() 从上到下打印堆栈中的项目。
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
*/
【讨论】:
【参考方案5】:Stack 从 AbstractList 继承 .listIterator(),允许逆序迭代。
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
【讨论】:
【参考方案6】:Eclipse Collections 包含一个mutable stack implementation,其中迭代器从上到下返回值。此代码打印 3、2,然后是 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
不扩展MutableCollection
或Collection
,例如,您无法从堆栈中间移除。实现内部迭代模式(如forEach()
、select()
、collect()
、anySatisfy()
、allSatisfy()
等)的方法也从上到下处理元素。此代码打印相同的内容。
stack.forEach(Procedures.println(System.out));
注意:我是 Eclipse 集合的提交者。
【讨论】:
【参考方案7】:您可以使用LinkedList
和push
和pop
方法来代替Stack
。
【讨论】:
以上是关于java.util.Stack 的迭代器中是不是有错误?的主要内容,如果未能解决你的问题,请参考以下文章