Пример невмешательства в Java 8 - PullRequest
0 голосов
/ 27 августа 2018

В соответствии с этим вопросом , мы можем изменить источник, и он не называется помехой:

вы можете изменить сами элементы потока, и его не следует называть "помехой".".

Согласно этот вопрос , код

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

не генерирует 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);

генерирует

Exception in thread "main" java.lang.UnsupportedOperationException
    at java.util.AbstractList.add(Unknown Source)
    at java.util.AbstractList.add(Unknown Source)
    at java8.Streams.lambda$0(Streams.java:33)
    at java.util.stream.ReferencePipeline$3$1.accept(Unknown Source)
    at java.util.Spliterators$ArraySpliterator.forEachRemaining(Unknown Source)
    at java.util.stream.AbstractPipeline.copyInto(Unknown Source)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
    at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(Unknown Source)
    at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(Unknown Source)
    at java.util.stream.AbstractPipeline.evaluate(Unknown Source)
    at java.util.stream.ReferencePipeline.forEach(Unknown Source)

Итак, я не совсем понимаю, какие модификации разрешены для источника, а какие нет.Было бы очень полезно увидеть пример, который мешает и имеет поток, создающий состояние и побочный эффект, с надлежащим указанием того, что есть что.

Ответы [ 6 ]

0 голосов
/ 27 августа 2018

Это называется структурным на неструктурным изменением источника Stream.Например, ArrayList doc говорит:

простая установка значения элемента не является структурной модификацией ...

Так что в вашем примере это означает, что изменение Employee per se, не изменяет сам 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.

0 голосов
/ 27 августа 2018

Когда вы делаете это:

li.stream().map(s->{s.setName("newname");return s;})

вы изменили не сам список, а элемент в этом списке ;поэтому он не вызывает ConcurrentModificationException, как вы ожидали.

В последнем фрагменте кода вы используете Array.asList.
Вы должны знать, что Array.asList возвращает просто Оболочка только для чтения над массивом (определенный внутренний класс ArrayList ), объясняющий, почему add не поддерживается.

Действительно, этот внутренний класс не переопределяет AbstractList # add method by design;причинение 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;)

0 голосов
/ 27 августа 2018

Ваш первый пример не изменяет исходный список.

Поток - это просто представление в списке, следовательно, initial список вовсе не зависит от вашего потокового кода.

В то время как второй пример явно использует list.add().

Это все, что нужно для этого.

0 голосов
/ 27 августа 2018

Ваш код изменяет элемент потока, а не сам список:

s->{s.setName("newname") изменяет имя поля в элементе потока, это не влияет на поток или его источник.

java.lang.UnsupportedOperationException также не связан, это вызвано тем, что вы пытаетесь вызвать add в списке фиксированного размера (который является результатом Arrays.asList).Каждый раз, когда вызывается add, remove и т. Д. По результату Arrays.asList, возникает исключение неподдерживаемой операции, так как сбор данных имеет фиксированный размер.

0 голосов
/ 27 августа 2018

Вы не можете изменить размер списка, над которым работаете.

В первом примере вы меняете значение объекта Employee внутри вашего списка.

Всекунду вы добавляете элемент в свой список.

В этом разница!

0 голосов
/ 27 августа 2018

Ваш первый пример изменяет существующие элементы Stream, но не добавляет и не удаляет элементы из источника.Поэтому это не помеха.

Ваш второй пример пытается создать помехи, добавляя элемент к источнику во время конвейера Stream.Однако вместо ConcurrentModificationException вы получаете UnsupportedOperationException, поскольку вы пытаетесь добавить элементы к фиксированному размеру 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.

...