web-dev-qa-db-fra.com

Modification d'objets dans un flux en Java8 lors de l'itération

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"))
51
Tejas Gokhale

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éristique CONCURRENT.

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
61
Pshemo

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

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.

1

Pour se débarrasser de ConcurrentModificationException Use CopyOnWriteArrayList  

0
black-coder

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.

0
Nicolas Zozol

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 + "]";
        }



    }
0
Joey587

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);
0
Jobin Joseph

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]
    }
}
0
Vadim