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 不扩展MutableCollectionCollection,例如,您无法从堆栈中间移除。实现内部迭代模式(如forEach()select()collect()anySatisfy()allSatisfy() 等)的方法也从上到下处理元素。此代码打印相同的内容。

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

注意:我是 Eclipse 集合的提交者。

【讨论】:

【参考方案7】:

您可以使用LinkedListpushpop 方法来代替Stack

【讨论】:

以上是关于java.util.Stack 的迭代器中是不是有错误?的主要内容,如果未能解决你的问题,请参考以下文章

concurrent_vector 迭代器的算术:假设从迭代器中减去“begin ()”会给出索引是不是安全?

java.util.Stack类中的peek()方法

迭代器中set的使用

Stack

java.util.Stack类简介

我什么时候应该使用java.util.Stack vs My Own Implementation? [关闭]