为了账号安全,请及时绑定邮箱和手机立即绑定

Java 8 中不干涉的例子

Java 8 中不干涉的例子

慕容森 2021-08-13 16:45:10
根据这个问题,我们可以修改源,它不称为干扰:您可以修改流元素本身,不应将其称为“干扰”。根据这个问题,代码List<String> list = new ArrayList<>();  list.add("test");  list.forEach(x -> list.add(x));会扔ConcurrentModificationException。但我的代码,Employee[] arrayOfEmps = {                new Employee(1, "Jeff Bezos"),                new Employee(2, "Bill Gates"),                new Employee(3, "hendry cavilg"),                new Employee(4, "mark cuban"),                new Employee(5, "zoe"),                new Employee(6, "billl clinton"),                new Employee(7, "ariana") ,                new Employee(8, "cathre"),                new Employee(9, "hostile"),                new Employee(10, "verner"),            };        Employee el=new Employee(1, "Jeff Bezos");        List<Employee> li=Arrays.asList(arrayOfEmps);        li.stream().map(s->{s.setName("newname");return s;}).forEach(System.out::print);不会 throw ConcurrentModificationException,即使它实际上改变了源。而这段代码,Employee[] arrayOfEmps = {                new Employee(1, "Jeff Bezos"),                new Employee(2, "Bill Gates"),                new Employee(3, "hendry cavilg"),                new Employee(4, "mark cuban"),                new Employee(5, "zoe"),                new Employee(6, "billl clinton"),                new Employee(7, "ariana") ,                new Employee(8, "cathre"),                new Employee(9, "hostile"),                new Employee(10, "verner"),            };        Employee el=new Employee(1, "Jeff Bezos");        List<Employee> li=Arrays.asList(arrayOfEmps);        li.stream().map(s->{s.setName("newname");li.add(s);return s;}).limit(10).forEach(System.out::print);因此,我不完全了解允许对源进行哪些类型的修改,哪些不允许。看到一个干扰并产生有状态和副作用的流的示例会非常有帮助,并正确指示哪个是哪个。
查看完整描述

3 回答

?
holdtom

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方法;)


查看完整回答
反对 回复 2021-08-13
?
陪伴而非守候

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.


查看完整回答
反对 回复 2021-08-13
?
慕尼黑5688855

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。


查看完整回答
反对 回复 2021-08-13
  • 3 回答
  • 0 关注
  • 194 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信