Dans les flux Java8, suis-je autorisé à modifier/mettre à jour des objets au sein de? List<User> users
:
users.stream().forEach(u -> u.setProperty("value"))
Oui, vous pouvez modifier l'état des objets dans votre flux, mais vous devez éviter de modifier l'état de source du flux. Dans la section non-ingérence de la documentation du paquet de flux, on peut lire que:
Pour la plupart des sources de données, empêcher les interférences signifie que la source de données est pas du tout modifiée} _ pendant l'exécution du pipeline de flux. L'exception notable à cette règle concerne les flux dont les sources sont des collections simultanées, spécialement conçues pour gérer les modifications simultanées. Les sources de flux simultanées sont celles dont
Spliterator
indique la caractéristiqueCONCURRENT
.
Donc c'est OK
List<User> users = getUsers();
users.stream().forEach(u -> u.setProperty(value));
mais
users.stream().forEach(u -> users.remove(u));
n'est pas et peut lancer ConcurrentModificationException
ou d'autres exceptions comme NPE:
List<Integer> list = IntStream.range(0, 10).boxed().collect(Collectors.toList());
list.stream()
.filter(i -> i > 5)
.forEach(i -> list.remove(i)); //throws NullPointerException
Pour effectuer une modification structurelle de la source du flux, comme Pshemo l’a mentionné dans sa réponse, une solution consiste à créer une nouvelle instance de Collection
comme ArrayList
avec les éléments de votre liste primaire; parcourez la nouvelle liste et effectuez les opérations de la liste principale.
new ArrayList<>(users).stream().forEach(u -> users.remove(u));
La manière fonctionnelle serait à mon sens:
import static Java.util.stream.Collectors.toList;
import Java.util.Arrays;
import Java.util.List;
import Java.util.function.Predicate;
public class PredicateTestRun {
public static void main(String[] args) {
List<String> lines = Arrays.asList("a", "b", "c");
System.out.println(lines); // [a, b, c]
Predicate<? super String> predicate = value -> "b".equals(value);
lines = lines.stream().filter(predicate.negate()).collect(toList());
System.out.println(lines); // [a, c]
}
}
Dans cette solution, la liste d'origine n'est pas modifiée, mais doit contenir le résultat attendu dans une nouvelle liste accessible sous la même variable que l'ancienne.
Pour se débarrasser de ConcurrentModificationException Use CopyOnWriteArrayList
Au lieu de créer des choses étranges, vous pouvez simplement filter()
puis map()
votre résultat.
C'est beaucoup plus lisible et sûr. Les flux le feront en une seule boucle.
C'est peut-être un peu tard. Mais voici l'un des usages. Ceci pour obtenir le nombre de fichiers.
Créez un pointeur sur la mémoire (un nouvel obj dans ce cas) et faites modifier la propriété de l'objet. Le flux Java 8 ne permet pas de modifier le pointeur lui-même. Par conséquent, si vous déclarez simplement compter comme une variable et essayez de l'incrémenter dans le flux, il ne fonctionnera jamais et lève une exception du compilateur
Path path = Paths.get("/Users/XXXX/static/test.txt");
Count c = new Count();
c.setCount(0);
Files.lines(path).forEach(item -> {
c.setCount(c.getCount()+1);
System.out.println(item);});
System.out.println("line count,"+c);
public static class Count{
private int count;
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
@Override
public String toString() {
return "Count [count=" + count + "]";
}
}
Vous pouvez utiliser la variable removeIf
pour supprimer des données d'une liste de manière conditionnelle.
Exemple: - Si vous souhaitez supprimer tous les nombres pairs d'une liste, vous pouvez le faire comme suit.
final List<Integer> list = IntStream.range(1,100).boxed().collect(Collectors.toList());
list.removeIf(number -> number % 2 == 0);
Comme il a été mentionné précédemment - vous ne pouvez pas modifier la liste d'origine, mais vous pouvez diffuser, modifier et collecter des éléments dans une nouvelle liste. Voici un exemple simple sur la façon de modifier un élément de chaîne.
public class StreamTest {
@Test
public void replaceInsideStream() {
List<String> list = Arrays.asList("test1", "test2_attr", "test3");
List<String> output = list.stream().map(value -> value.replace("_attr", "")).collect(Collectors.toList());
System.out.println("Output: " + output); // Output: [test1, test2, test3]
}
}