迭代器能否更改它正在迭代的集合?JAVA

迭代器能否更改它正在迭代的集合?JAVA,java,iterator,Java,Iterator,我试图使用迭代器的迭代次数作为计数器,但我想知道这样做的后果 private int length(Iterator<?> it) { int i = 0; while(it.hasNext()) { it.next(); i++; } return i; } private int length(迭代器){ int i=0; while(it.hasNext()){ it.next(); i++; } 返回i;

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

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

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

    return i;
}
private int length(迭代器){
int i=0;
while(it.hasNext()){
it.next();
i++;
}
返回i;
}
这很好,但我担心迭代器在幕后会做什么。也许当我在堆栈上迭代时,它会弹出堆栈中的项目,或者如果我使用的是优先级队列,它会修改优先级

javadoc对迭代器这样说:

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


我看不出迭代这个未知集合不会修改它的保证。我是在考虑不现实的边缘案例,还是这是一个问题?有更好的方法吗?

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

请记住,如果您修改由
next()
返回的对象,这些更改将出现在您的集合中。

仔细想想——返回内容的方法是(如果编写正确的话)访问器方法,这意味着它们只返回数据。它们不会修改它(它们不是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++);
    }
}
public类ArraySetIterator实现迭代器
{
私有int nextIndex;
私人住宅区;
公共阵列滴定仪(阵列集a)
{
this.nextIndex=0;
this.thearray=a;
}
公共布尔hasNext()
{
返回this.nextIndex
据我所知,
集合
规范没有明确说明迭代集合不会修改它,但标准库中没有任何类显示该行为(实际上至少有一个显示,请参见),因此任何这样做的类都会受到高度怀疑。我认为你不必为此担心


请注意,
Guava
库以与您相同的方式实现和,因此显然,它们在一般情况下是安全的。

迭代器只是为某种流提供了一个接口,因此,
next()
不仅完全可能以某种方式销毁数据,但是,
迭代器
中的数据甚至可能是唯一的和不可替代的

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

Path dir = ...
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
  int count = length(stream.iterator());
  for (Path entry: stream) {
    ...
  }
}
路径目录=。。。 try(DirectoryStream=Files.newDirectoryStream(dir)){ int count=长度(stream.iterator()); for(路径条目:流){ ... } }
在foreach块中会出现异常,因为流只能迭代一次。总之,您的
length()
方法有可能更改对象并丢失数据

此外,
迭代器
没有理由必须与某个单独的数据存储相关联。例如,ago提供了一种选择
n
随机数的干净方法。通过使用无限的
迭代器,我们能够提供、过滤和惰性地传递任意数量的随机数据,无需一次存储所有数据,甚至在需要之前计算它们。因为迭代器不支持任何数据结构,所以查询它显然是破坏性的


话虽如此,这些例子并不会让你的方法变得糟糕。请注意(每个人都应该使用的)提供了一个类,该类的行为与您在上面详述的完全相同,调用该类是为了符合集合框架。这样一来,这些方法的用户就要意识到他们处理的是什么样的数据,并避免进行粗心的调用,例如试图在
迭代器中计算他们知道无法替换的结果的数量。

这是一种合理的行为,但会被“修改”的集合当被迭代时,仍然会遵守迭代契约(显然),这就是问题所在。迭代集合(集合框架中的某些内容)不会修改集合,然而,这并不意味着一些任意定义的
迭代器
Iterable
如果选择的话就不能这样做。考虑一个返回随机数的<代码> Iterator <代码>;一旦调用了
next()
,该数字实际上就“消失了”。是的,通常
Iterator
不会修改。OP询问特殊情况。不修改其数据的示例
迭代器
。没有一成不变的规则规定返回值的方法永远不会改变状态。+1。请注意,即使
java.util.Iterator
确实指定了类似的内容,它实际上也不是绑定需求。一个类实际上并不符合其接口的契约,这种情况经常发生。(例如,JDK的
java.util.IdentityHashMap
完全、故意和文档化地违反了
java.util.Map
的一般契约)除
集合的子对象之外的对象可以拥有或是
迭代器