web-dev-qa-db-fra.com

Exemple de non-ingérence en Java 8

Selon cette question , nous pouvons modifier la source et ce n’est pas appelé interférence:

vous pouvez modifier les éléments de flux eux-mêmes et il ne faut pas appeler cela "interférence".

Selon cette question , le code

List<String> list = new ArrayList<>();
  list.add("test");
  list.forEach(x -> list.add(x));

va jeter ConcurrentModificationException.

Mais mon code,

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

ne jette pas ConcurrentModificationException, même si cela change le code source.

Et ce code,

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

jette

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)

Donc, je ne comprends pas exactement quel type de modifications sont autorisées à la source et lesquelles ne le sont pas. Il serait très utile de voir un exemple qui interfère et a un flux produisant des effets de bord et des effets secondaires, avec une indication appropriée de ce qui est qui.

12
amarnath harish

Votre premier exemple modifie les éléments existants de la Stream, mais n’ajoute ni ne supprime d’éléments de la source. Par conséquent, ce n'est pas une ingérence.

Votre deuxième exemple tente d’interférer en ajoutant un élément à la source pendant le pipeline Stream. Cependant, vous obtenez UnsupportedOperationException au lieu de ConcurrentModificationException puisque vous essayez d'ajouter des éléments à une List de taille fixe (qui est retournée par Arrays.asList).

Changez votre deuxième exemple en:

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

et vous devriez obtenir ConcurrentModificationException.

5
Eran

Ceci est appelé un structurel sur non structurel changement de la source de la Stream. Par exemple, ArrayList doc dit:

définir simplement la valeur d'un élément n'est pas une modification structurelle ...

Ainsi, dans votre exemple, cela signifie que changer Employee en soi ne change pas la List elle-même (ne supprime ni n'ajoute d'élément). Mais changer la List elle-même échouera avec une ConcurrentModificationException:

List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);

list.stream().forEach(x -> list.remove(x));

Mais il existe des sources d'interférence plus que correctes, appelées traversée faiblement cohérente , comme 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()));

Cela n'échouera pas avec ConcurrentModificationException.

4
Eugene

Vous ne pouvez pas changer la taille de la liste sur laquelle vous travaillez.

Dans le premier exemple, vous modifiez une valeur de l'objet Employee dans votre liste.

Dans la seconde, vous ajoutez un élément à votre liste.

C'est la différence!

2
Leviand

Votre code modifie l'élément de flux, pas la liste elle-même:

s->{s.setName("newname") modifie un nom de champ dans l'élément du flux, cela n'interfère pas avec le flux ou sa source.

Le Java.lang.UnsupportedOperationException est également indépendant, cela est dû au fait que vous essayez d'appeler add sur une liste de taille fixe (résultat de Arrays.asList) . Chaque fois que vous appelez add, remove, etc. sur le résultat de Arrays.asList , l'exception d'opération non prise en charge est déclenchée, car la taille de la collecte est fixe.

2
ernest_k

Votre premier exemple modifie la liste initiale de not.

Un flux est juste une vue vue sur la liste, donc la liste initiale est pas du tout affectée par votre code de flux.

Alors que le deuxième exemple utilise explicitement list.add()

C'est tout ce qu'il y a à cela.

2
GhostCat