我从0-9(Integer)下面定义了列表:
List<Integer> list = 
                IntStream.range(0, 10)
                         .boxed()
                         .collect(Collectors.toCollection(ArrayList::new));
当我尝试使用以下代码删除元素时:
list.stream()
            .peek(list::remove)
            .forEach(System.out::println);
它应该抛出,ConcurrentModificationException但有趣的是它适用于某些元素并提供以下输出(在最后抛出异常并删除了一些元素):
0
2
4
6
8
null
null
null
null
null
Exception in thread "main" java.util.ConcurrentModificationException
但如果我添加sorted()如下:
list.stream()
            .sorted()
            .peek(list::remove)
            .forEach(System.out::println);
这非常好,并删除了所有元素,我很困惑为什么stream这样做.
Ano*_*sse 11
您是否查看了源代码如何实现这些类?
该方法sorted()将复制您的列表以进行排序.
因此它的行为有所不同:您正在迭代已排序的副本,但仅从第一个列表中删除.
peek不鼓励使用该方法; 来自JavaDoc:
此方法主要用于支持调试
System::println为了开发目的而放置一个或类似的东西是可以的,但它不是你应该用于最终程序的功能.
阅读流包的API规范:
https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#NonInterference
对于大多数数据源,防止干扰意味着确保在流管道的执行期间根本不修改数据源.
因此,换句话说:您不能从列表中删除当前正在流式传输的列表,但无法保证它将起作用.
你的初始名单是
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]        pos = 0
您打印0并删除它,然后前进到下一个位置.然后是新阵列
[1, 2, 3, 4, 5, 6, 7, 8, 9, null]     pos = 1
在下一位置值是现在2,那么打印和删除2:
[1, 3, 4, 5, 6, 7, 8, 9, null, null]  pos = 2
等等.问题是,由于你的并发删除,列表的其余部分继续向前发展.
将ConcurrentModificationException在抛出流的结束.这似乎是一个性能决策(仅检查一次并发修改,而不是每次迭代)forEachRemaining,因此这个流不是快速失败的