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.
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
.
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
.
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!
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.
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.