Java 8 中不干涉的例子

根据这个问题,我们可以修改源,它不称为干扰:


您可以修改流元素本身,不应将其称为“干扰”。


根据这个问题,代码


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

因此,我不完全了解允许对源进行哪些类型的修改,哪些不允许。看到一个干扰并产生有状态和副作用的流的示例会非常有帮助,并正确指示哪个是哪个。


慕容森
浏览 195回答 3
3回答

holdtom

当你这样做时: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) {&nbsp; &nbsp; Employee[] arrayOfEmps = {&nbsp; &nbsp; &nbsp; new Employee(1, "Jeff Bezos")&nbsp; &nbsp; };&nbsp; &nbsp; Employee el = new Employee(11, "Bill Gates");&nbsp; &nbsp; List<Employee> li = new ArrayList<>(Arrays.asList(arrayOfEmps)); // to avoid read-only restriction&nbsp; &nbsp; li.stream().peek(s -> li.add(el)).forEach(System.out::print);}&nbsp;请注意,我Arrays.List用 "true"包装返回ArrayList,允许写入,因为它实现了该add方法;)

陪伴而非守候

您的第一个示例更改 的现有元素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.

慕尼黑5688855

这称为 . 来源的结构性对非结构性变化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:&nbsp;ConcurrentHashMap<Integer, String> chm = new ConcurrentHashMap<>();&nbsp;chm.put(1, "one");&nbsp;chm.put(2, "two");&nbsp;chm.put(3, "three");&nbsp;chm.entrySet().stream()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.forEach(x -> chm.remove(x.getKey()));这不会失败ConcurrentModificationException。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java