【发布时间】:2018-12-01 22:19:14
【问题描述】:
当我运行以下代码时
List<Integer> list = IntStream.range(0,10).boxed().collect(Collectors.toList());
list.stream().forEach(i -> {
System.out.println("i:" +i);
if (i==5) {
System.out.println("..adding 22");
list.add(22);
}
});
我得到以下输出:
i:0
i:1
i:2
i:3
i:4
i:5
..adding 22
i:6
i:7
i:8
i:9
Exception in thread "main" java.util.ConcurrentModificationException
为什么代码超过索引 5?我没想到输出中会出现以下几行:
i:6
i:7
i:8
i:9
我在这里遗漏了一些东西,可能是关于 forEach 的行为。 该文档确实声明“此操作的行为是明确的不确定性”。并继续讨论并行流。我希望并行流以任何顺序执行 forEach,但串行流肯定会执行消费者连续馈送到 forEach 吗?如果是这样,为什么 Java 允许代码超出索引 5 处生成的异常?这里有一个线程,对吗?
提前谢谢你。
编辑: 感谢您到目前为止的回答。绝对清楚我的观点是,如果我这样做:
for(int i: list){
System.out.println("i:" +i);
if(i==5) {
System.out.println("..adding 22");
list.add(22);
}
}
我明白了:
i:0
i:1
i:2
i:3
i:4
i:5
..adding 22
Exception in thread "main" java.util.ConcurrentModificationException
但我没有在 forEach 中得到它。 因此,似乎串行流 forEach 并不类似于迭代器,无论是手动(Iterator iter = list.iterator ...)还是增强的 for 循环迭代器。这出乎我的意料。但从答案看来,这是出于“性能原因”。但还是……出乎意料。 只是为了好玩,我尝试了 1m 个元素的列表:
List<Integer> list = IntStream.range(0,1000000).boxed().collect(Collectors.toList());
list.stream().forEach(
i -> {
if(i%250000==0)
System.out.println("i:" +i);
if(i>999997)
System.out.println("i:" +i);
if(i==5) {
System.out.println("..adding 22");
list.add(22);
}}
);
我得到了(现在预期的)以下输出:
i:0
..adding 22
i:250000
i:500000
i:750000
i:999998
i:999999
Exception in thread "main" java.util.ConcurrentModificationException
如前所述,检查似乎在最后完成。
【问题讨论】:
-
beyond index 5 是一个实现细节,下个版本可能会beyond 3,重点是
list.add(22);打破了不干涉。
标签: java list lambda java-8 java-stream