3 回答
TA贡献1805条经验 获得超10个赞
当你这样做时:
li.stream().map(s->{s.setName("newname");return s;})
您没有更改列表本身,而是更改了此列表中的一个元素;所以它不会ConcurrentModificationException像你预期的那样触发 a 。
在最后一个代码片段中,您使用的是Array.asList.
您必须知道在数组(一个特定的内部 ArrayList类)上Array.asList返回一个只读包装器,解释为什么不支持。 add
事实上,这个内部类并没有在设计上覆盖AbstractList#add方法;造成UnsupportedOperationException; 仍然不像ConcurrentModificationException你预期的那样。
这是一个类似于您的最后一个片段的示例,它确实抛出了一个ConcurrentModificationException:
public static void main(String[] args) {
Employee[] arrayOfEmps = {
new Employee(1, "Jeff Bezos")
};
Employee el = new Employee(11, "Bill Gates");
List<Employee> li = new ArrayList<>(Arrays.asList(arrayOfEmps)); // to avoid read-only restriction
li.stream().peek(s -> li.add(el)).forEach(System.out::print);
}
请注意,我Arrays.List用 "true"包装返回ArrayList,允许写入,因为它实现了该add方法;)
TA贡献1757条经验 获得超8个赞
您的第一个示例更改 的现有元素Stream,但不会从源中添加或删除元素。因此,这不是干扰。
您的第二个示例尝试通过在Stream管道期间向源添加元素来进行干扰。但是,您得到了UnsupportedOperationException而不是ConcurrentModificationException,因为您尝试将元素添加到固定大小List(由 返回Arrays.asList)。
将您的第二个示例更改为:
List<Employee> li=new ArrayList<>(Arrays.asList(arrayOfEmps));
li.stream().map(s->{s.setName("newname");li.add(s);return s;}).limit(10).forEach(System.out::print);
你应该得到ConcurrentModificationException.
TA贡献1848条经验 获得超2个赞
这称为 . 来源的结构性对非结构性变化Stream。例如ArrayListdoc 说:
仅仅设置元素的值不是结构修改......
因此,在您的示例中,这意味着更改Employee本身不会更改List本身(不会删除或添加元素)。但是改变List本身,将失败ConcurrentModificationException:
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.stream().forEach(x -> list.remove(x));
但是有些来源的干扰不仅仅是可以的,称为弱一致遍历,例如ConcurrentHashMap:
ConcurrentHashMap<Integer, String> chm = new ConcurrentHashMap<>();
chm.put(1, "one");
chm.put(2, "two");
chm.put(3, "three");
chm.entrySet().stream()
.forEach(x -> chm.remove(x.getKey()));
这不会失败ConcurrentModificationException。
添加回答
举报