为什么iterator.forEachRemaining不会删除Consumer lambda中的元素?

aza*_*lut 11 lambda listiterator java-8

让我们来看看这个例子:

public class ListIteratorTest {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("element1");
        list.add("element2");
        list.add("element3");
        list.add("element4");

        ListIterator<String> iterator = list.listIterator();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,这很好用:

    // prints elements out, and then appropriately removes one after another
    while (iterator.hasNext()){
        System.out.println(iterator.next());
        iterator.remove();
    }
Run Code Online (Sandbox Code Playgroud)

虽然这会抛出IllegalStateException:

        // throws IllegalStateException, why?
        iterator.forEachRemaining(n -> {
            System.out.println(n);
            iterator.remove();
        });
Run Code Online (Sandbox Code Playgroud)

我的问题很简短:为什么?

aio*_*obe 17

感谢@studro.请参阅下面的评论.

API文档状态:

如果在迭代正在进行中以除调用此方法之外的任何方式修改基础集合,则未指定迭代器的行为.

看起来"未指定的行为"部分也适用于此内部迭代.

当然,该forEachRemaining行为等同的状态的文档

while (hasNext())
    action.accept(next());
Run Code Online (Sandbox Code Playgroud)

如果action::accept确实调用iterator.remove()上面的代码段不应该抛出任何异常(如果remove是支持的操作).这可能是文档错误.

  • ...或者只是`list.removeIf(...)`如果你想用惯用的java 8方式修改列表. (5认同)
  • 当然.您可以将待删除元素存储在单独的列表`toDelete`中,并且在forEachRemaining完成后,您可以使用`list.removeAll(toDelete)`.然而,这不是在Java 8中解决它的惯用方法.您可能想要使用`stream.filter`. (3认同)