迭代器可以改变迭代的集合吗? Java的

时间:2014-01-12 22:49:57

标签: java iterator

我试图使用迭代器中的迭代次数作为计数器,但是想知道这样做的后果。

private int length(Iterator<?> it) {
    int i = 0;

    while(it.hasNext()) {
        it.next();
        i++;
    }

    return i;
}

这很好用,但我担心迭代器可能会在幕后做什么。也许当我在堆栈上迭代时,它会弹出堆栈中的项目,或者如果我使用优先级队列,它会修改优先级。

javadoc说这是关于iterator:

  


  E next()
  返回迭代中的下一个元素   返回:
  迭代中的下一个元素
  抛出:
  NoSuchElementException - 如果迭代没有更多元素

我没有看到保证迭代这个未知的集合不会修改它。我是在考虑不切实际的边缘情况,还是这是一个问题?还有更好的方法吗?

4 个答案:

答案 0 :(得分:5)

Iterator只是为某种流提供了一个接口,因此next()不仅可以以某种方式破坏数据,而且甚至可以对{{1}中的数据进行破坏。 1}}是唯一且不可替代的。

我们可以提出更直接的示例,但一个简单的示例是DirectoryStream中的Iterator。虽然Iterator在技术上是DirectoryStream,但它只允许构建一个Iterable,因此如果您尝试执行以下操作:

Iterator

您将在foreach块中获得异常,因为该流只能迭代一次。总而言之,您的Path dir = ... try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) { int count = length(stream.iterator()); for (Path entry: stream) { ... } } 方法可能会更改对象并丢失数据。

此外,没有理由length()必须与某个单独的数据存储相关联。以answer I gave a few months之前的例子为例,提供一种选择Iterator随机数的简洁方法。通过使用无限n,我们能够懒惰地提供,过滤和传递任意大量的随机数据,无需一次性存储,甚至计算它们直到需要它们。因为Iterator不支持任何数据结构,所以查询它显然具有破坏性。

现在说,这些例子不会让你的方法变坏。请注意,Guava library(每个人都应该使用)提供了一个Iterators类,其中包含您在上面详述的行为,称为size()以符合集合框架。然后,这些方法的用户需要知道他们正在使用什么类型的数据,并避免进行不小心的调用,例如尝试计算他们知道不能的Iterator中的结果数量。替换。

答案 1 :(得分:4)

据我所知,Collection规范并未明确声明迭代集合不会修改它,但标准库中没有类显示该行为(实际上至少有一个,见dimo414's answer),所以任何上课的人都会非常怀疑。我认为你不必担心这个。

请注意,Guava库以与您相同的方式实现Iterators.size()Iterables.size(),因此很明显他们在一般情况下会发现它是安全的。

答案 2 :(得分:2)

不,迭代集合不会修改集合。 Iterator类确实有remove()方法,这是在迭代期间从集合中删除元素的唯一安全方法。但只是调用hasNext()next()不会修改集合。

请注意,如果您修改next()返回的对象,则这些更改将出现在您的收藏中。

答案 3 :(得分:0)

考虑一下 - 返回事物的方法(如果它们被正确编写)访问器方法,意味着它们只返回数据。他们不修改它(它们不是mutator方法)。

这是我在磁盘上有关如何实现迭代器的示例。如您所见,实际上没有修改任何值。

public class ArraySetIterator implements Iterator
{
    private int nextIndex;
    private ArraySet theArraySet;

    public ArraySetIterator (ArraySet a)
    {
        this.nextIndex = 0;
        this.theArraySet = a;
    }

    public boolean hasNext ()
    {
        return this.nextIndex < this.theArraySet.size();
    }

    public Object next()
    {
        return this.theArraySet.get(this.nextIndex++);
    }
}