在下面的代码中,我希望迭代可以运行3次。最初,迭代器有1个“下一个”,但是在第一次迭代中,又向迭代器添加了两个值,因此应该再有两个“下一个”,即iterator.hasNext()
应该为真。
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class Foo {
public static void main(String[] args) {
List<String> strings = new ArrayList<>();
strings.add("A");
ListIterator<String> iterator = strings.listIterator();
int i = 0;
while (iterator.hasNext()) {
i++;
String str = iterator.next();
if (str.equals("A")) {
iterator.add("B");
iterator.add("C");
}
// strings.remove(str);
// iterator = strings.listIterator();
}
System.out.println("The iteration was run " + i + " times");
}
}
但是它只能运行一次。解决方法是,我可以从原始列表中删除当前迭代,然后重置迭代器(带注释的行)。但是为什么这是必要的?迭代器不应该已经知道它有更多的值可以迭代吗?
答案 0 :(得分:1)
迭代器是否已经不知道它有更多的值要迭代?
不,不应该。如果您查看add()
here的文档,则可以在其中找到以下句子
对next的后续调用将不受影响,而对previous的后续调用将返回新元素。 (此调用将对nextIndex或previousIndex的调用返回的值增加一个。)
很明显,添加新元素不会影响您当前的循环流。另外,如果您查看ListIterator
的{{1}}实现的源代码:
ArrayList
...
public E next() {
checkForComodification();
int i = cursor;
if (i >= SubList.this.size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (offset + i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[offset + (lastRet = i)];
}
public void add(E e) {
checkForComodification();
try {
int i = cursor;
SubList.this.add(i, e);
cursor = i + 1;
lastRet = -1;
expectedModCount = ArrayList.this.modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
变量指向cursor
用于返回下一个元素的位置。如您所见,next()
和cursor
的大小都会增加。因此,实际上,SubList
已调整为跳过“旧”的下一个位置,而转向“新”的下一个位置。每次调用cursor
时,add()
都会相应地进行调整。要获取新元素,您应该使用cursor
或重新开始循环。
此外,您的情况可以如下所示:
previous()
在添加 cursor
|
V
0 1
A
和B
之后,C
仍然指向不存在的元素:
cursor