Java:为什么在使用 Stream+Iterator 时不会发生 ConcurrentModificationException?

Ant*_*aaa 4 java iterator arraylist java-8 java-stream

我正在阅读一些关于迭代器、枚举等的信息。所以我测试了一些代码来检查所有内容。

第一个例子:

List<String> list = new ArrayList<>();
list.add("5");
list.add("1");
list.add("2");
list.add("3");
Iterator<String> iterator = list.iterator();
list.remove("1");
iterator.forEachRemaining(System.out::println);
Run Code Online (Sandbox Code Playgroud)

此代码生成正确和预期的输出:

Exception in thread "main" java.util.ConcurrentModificationException
Run Code Online (Sandbox Code Playgroud)

但是当我测试相同的代码时,只有 1 个更改 list.iterator()->list.stream().iterator()

List<String> list = new ArrayList<>();
list.add("5");
list.add("1");
list.add("2");
list.add("3");
Iterator<String> iterator = list.stream().iterator();
list.remove("1");
iterator.forEachRemaining(System.out::println);
Run Code Online (Sandbox Code Playgroud)

结果是:

5
2
3
Run Code Online (Sandbox Code Playgroud)

我的主要目的是了解:

  1. 为什么会发生这种情况?
  2. 什么魔法只产生一种stream()方法?
  3. 使用的优点和缺点是stream().iterator什么?

And*_*eas 5

当您调用时stream(),API 会在内部调用spliterator(),这与iterator().

对于ArrayList,返回的Spliterator/Iterator使用一个expectedModCount字段modCount与列表的字段进行比较,以检查列表是否已被修改。

的实现在创建迭代器时Iterator初始化expectedModCount字段。

的实现Spliterator将初始化推迟到从Spliterator.

这意味着它允许在调用stream()和调用实际开始从流中提取数据的终端操作之间修改列表。

  • 这些是技术(实施)细节。更重要的方面是`ArrayList`的`stream()`方法返回一个[后期绑定](https://docs.oracle.com/javase/8/docs/api/java/util/Spliterator.html #绑定)`流`。它也在[包文档的非干扰部分](https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#NonInterference)中指定:“*对于表现良好的流源,可以在终端操作开始之前修改源,这些修改将反映在所覆盖的元素中。*”示例... (4认同)