为什么iterator.ForEachRestaining不删除使用者lambda中的元素?

为什么iterator.ForEachRestaining不删除使用者lambda中的元素?,lambda,java-8,listiterator,Lambda,Java 8,Listiterator,让我们看看这个例子: public class ListIteratorTest { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("element1"); list.add("element2"); list.add("element3"); list.

让我们看看这个例子:

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();
    }
}
虽然这会引发非法状态异常:

        // throws IllegalStateException, why?
        iterator.forEachRemaining(n -> {
            System.out.println(n);
            iterator.remove();
        });
我的问题很简短:为什么

由于@studro更新。见下面他的评论

各国:

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

“未指定行为”部分似乎也适用于此内部迭代

诚然,
forEachRemaining
的文档声明该行为等同于

while (hasNext())
    action.accept(next());

如果
action::accept
确实调用了
iterator.remove()
上述代码段不应引发任何异常(如果
remove
是受支持的操作)。这可能是一个文档错误。

那么,是否可以使用lambdas(例如iterator.forEachRemaining())遍历列表并在对其进行操作后删除元素?当然可以。您可以将要删除的元素存储在一个单独的列表中,
toDelete
,在forEachRemaining完成后,您可以使用
list.removeAll(toDelete)
。然而,在Java8中,这并不是解决这个问题的惯用方法。您可能想使用
流.filter
。。。。或者,如果您想以惯用的java 8方式就地修改列表,只需
list.removeIf(…)
。@aioobe-hm。。让我们假设我从ServiceClass接收到一些对象的列表。我希望对这个列表进行迭代,对于每个元素都应该做一些事情,然后删除对象(所以最后列表被销毁)。过滤器在这里有什么用处?这是两个终端操作,所以它们不应该(不能)混合。我建议使用两个单独的迭代。一个
.forEach
和一个
removeIf
(正如@alexic.所指出的)。Lambda表达式(当然还有方法引用)在创建可读性更高或更干净的代码方面具有巨大优势。在可读性方面,我倾向于在任何我真正受益的地方使用它们。与不使用lambda表达式的示例相比,lambda示例的可读性不是更高,也不是更低。事实上,它有相同数量的代码行。那么,为什么您觉得必须(或应该)在这里使用lambdas呢?事实上你发现了。。。它们使您的代码有点复杂,因为您不应该在lambda中使用迭代器。@Seelenvirtuose我仍在学习Java8的功能,所以我尝试在任何地方使用lambdas等。我只是想,如果可能的话,我想检查一下——结果出人意料,我不知道为什么在这里这么问;但是,感谢您解释lambas的实际用途——尽可能简单
while (hasNext())
    action.accept(next());