我已经从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
会这样做。
答案 0 :(得分: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
等等。问题是,由于你的并发删除,列表的其余部分继续向前发展。
{<1}}会在流的端抛出。这似乎只是ConcurrentModificationException
的性能决策(仅针对并发修改检查一次,而不是每次迭代),因此此流不是快速失败