当我运行以下代码时
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循环迭代器。这对我来说是意外的。但是从答案看来,这似乎是出于“性能原因”。但这仍然是...意想不到的。 只是为了踢球,我尝试了一个100万个元素的列表:
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
如上所述,检查似乎已经结束。
答案 0 :(得分:8)
您看到的行为特定于ArrayListSpliterator
在Stream
上使用的ArrayList
。
代码中的注释说明了实现选择:
在
的末尾,我们仅执行一次ConcurrentModificationException
(对性能最敏感的方法)[JDK 8 source code]forEach
检查
这与并发修改检查的约定一致。在进行修改的情况下,不需要迭代器快速失败。如果他们确实选择快速失败,则实施者可以决定实施检查的严格程度。例如,如上所述,通常需要在正确性和性能之间进行权衡。
检测到对象并发修改的方法可能抛出此异常。 [...]快速运行操作会尽最大努力抛出
ConcurrentModificationException
。因此,编写依赖于此异常的程序的正确性是错误的:ConcurrentModificationException
仅应用于检测错误。 [Java SE 8 API docs]
答案 1 :(得分:5)
好吧,在ArrayListSpliterator
下有一条评论:
如果ArrayList是不可变的或结构上不可变的(没有添加,删除等),我们可以使用Arrays.spliterator实现它们的分隔符。取而代之的是,我们在遍历过程中发现了尽可能多的干扰,而又不牺牲太多性能
因此,没有按元素进行对何时在源List
上发生干扰的检查(可能我对实现没有过多研究),但是在其他时候,主要目标将是不要牺牲性能,但是在“编辑”源代码时仍然会失败。
您仍然违反non-interference
,并且在这种情况下,您的代码仍然会失败,而不是更快。
答案 2 :(得分:-1)
更新您的代码:使用CopyOnWriteArrayList
Error in charToDate(x) :
character string is not in a standard unambiguous format