Java 列表迭代器非法状态异常
有这个班Java 列表迭代器非法状态异常,java,list,iterator,Java,List,Iterator,有这个班 public class IteratorStuff { private static final String EMPTY = ""; public static void main(String[] args) { System.out.println("success:"); success(newCollection()); System.out.println("fail:"); fail(n
public class IteratorStuff {
private static final String EMPTY = "";
public static void main(String[] args) {
System.out.println("success:");
success(newCollection());
System.out.println("fail:");
fail(newCollection());
}
private static void fail(Collection<String> myCollection) {
Iterator<String> iterator = myCollection.iterator();
iterator.forEachRemaining(new Consumer<String>() {
public void accept(String s) {
if (s != EMPTY)
System.out.println("string = " + s);
else
iterator.remove();
}
});
}
private static Collection<String> newCollection() {
Collection<String> myList = new LinkedList<String>();
myList.add(EMPTY);
myList.add("1");
myList.add("2");
myList.add("3");
return myList;
}
private static void success(Collection<String> myCollection) {
Iterator<String> iterator = myCollection.iterator();
while (iterator.hasNext()) {
String s = iterator.next();
if (s != EMPTY)
System.out.println("string = " + s);
else
iterator.remove();
}
}
}
公共类迭代器tuff{
私有静态最终字符串为空=”;
公共静态void main(字符串[]args){
System.out.println(“成功:”);
成功(newCollection());
System.out.println(“失败:”);
失败(newCollection());
}
私有静态无效失败(收集myCollection){
迭代器迭代器=myCollection.Iterator();
iterator.forEachRemaining(新使用者(){
公共无效接受(字符串s){
如果(s!=空)
System.out.println(“string=“+s”);
其他的
iterator.remove();
}
});
}
私有静态集合newCollection(){
集合myList=新的LinkedList();
myList.add(空);
myList.添加(“1”);
myList.添加(“2”);
myList.添加(“3”);
返回myList;
}
私有静态无效成功(收集myCollection){
迭代器迭代器=myCollection.Iterator();
while(iterator.hasNext()){
字符串s=迭代器.next();
如果(s!=空)
System.out.println(“string=“+s”);
其他的
iterator.remove();
}
}
}
它在字符串集合上迭代,删除一个特定的空字符串并打印其他字符串。成功(收集)实现工作正常
失败的一个以一个非法的状态例外而中断。但是,它能够从迭代器中获取空字符串。这表明next()一定被调用了。另外,在默认ForEachResisting实现中
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
defaultvoid forEachRemaining(消费者问题可能是-
您正在使用迭代器并同时修改它
private static void fail(Collection<String> myCollection) {
Iterator<String> iterator = myCollection.iterator();
iterator.forEachRemaining(new Consumer<String>() {
public void accept(String s) {
if (s != EMPTY)
System.out.println("string = " + s);
else
iterator.remove();
}
});
}
私有静态无效失败(收集myCollection){
迭代器迭代器=myCollection.Iterator();
iterator.forEachRemaining(新使用者(){
公共无效接受(字符串s){
如果(s!=空)
System.out.println(“string=“+s”);
其他的
iterator.remove();
}
});
}
您正在使用迭代器对象调用ForEachRestaining方法,并且在该方法中还将从同一迭代器中删除该对象
未来读者:这个答案不正确!
尽管提问者已经接受了这个答案作为他们问题的解决方案,但它可能[对其他人或一般人]不起作用。请参见Andreas对问题的更透彻的分析
如果查看GrepCode中LinkedList$ListItr
(由LinkedList#iterator()
返回的ListIterator
实现)的代码,您会发现它不会更新迭代器本身,而是从当前元素开始,并使用局部变量进行迭代
这意味着迭代器本身(您从未在其上调用过next()
)无效。即使您在进入循环之前调用了next()
,它也会删除错误的元素,并且还可能导致ConcurrentModificationException
,因为它的位置没有被ForEachRestain()更新
和项删除会干扰迭代器
关于Java库的任何问题,如果无法从Javadoc中解决,请参阅参考资料。使用它。
问题在于您使用的是链接列表
,并且它本身的缺陷实现了foreachresaining()
:
由于remove()
检查lastReturned
的值,因此需要在调用accept()
之前设置该值
提交一个bug
更新
有一个类似的问题,WAREcursor
和lastRet
在迭代过程中没有设置,因此尽管foreachrestaining()
的javadoc没有明确说明您不能使用Iterator.remove()
或ListIterator.add()
,但当前的实现显然没有预料到您会这样做
它们甚至不会以一致的方式失败或防护,因此它们与正常的快速失败策略不一致
因此,为文档和/或fail fast逻辑提交一个bug可能更合适。因为ForEachLeving是迭代器中的默认方法。真的不明白你在问什么……我不希望看到迭代器的remove()
在forEachRemaining
的上下文中工作,因为它可能没有在内部使用迭代器。它在success
的情况下工作良好,因为您正在使用迭代器并删除当前元素。但是,我没有文档参考,所以我将此作为注释发布。因为forEachRemaining()
没有指定它的迭代方式,代码中的迭代器没有可用的理由。请参见此处:@JimGarrison是的,我意识到它很成功,因为它已经按预期使用了很长一段时间。但是foreachrestain(最后在默认实现中)确实调用next()并将结果传递给行动。有趣的问题。我喜欢没有明显答案的问题,让我去看:-)不能在答案部分发表评论。这是一个很好的观点。使用者
方法的主体应视为单个操作。在该操作期间,迭代器的状态未定义。当使用者方法正在运行时,如果您试图调用迭代器上的其他方法,迭代器有权感到不安。在这种情况下,正常while hasNext循环的迭代应该被视为单个操作?我不确定这是否有意义。你在看什么源代码?openjdk源代码在LinkedList$ListItr.ForEachLeving()
中不使用局部变量。看,很有趣。。。。你说得对。OP应该接受你的回答
public void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (modCount == expectedModCount && nextIndex < size) {
action.accept(next.item);
lastReturned = next;
next = next.next;
nextIndex++;
}
checkForComodification();
}
public E next() {
checkForComodification();
if (!hasNext())
throw new NoSuchElementException();
lastReturned = next;
next = next.next;
nextIndex++;
return lastReturned.item;
}
public void remove() {
checkForComodification();
if (lastReturned == null)
throw new IllegalStateException();
Node<E> lastNext = lastReturned.next;
unlink(lastReturned);
if (next == lastReturned)
next = lastNext;
else
nextIndex--;
lastReturned = null;
expectedModCount++;
}
public void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (modCount == expectedModCount && nextIndex < size) {
lastReturned = next;
next = next.next;
nextIndex++;
action.accept(lastReturned.item);
}
checkForComodification();
}