web-dev-qa-db-fra.com

Prise en compte des éléments de liste ajoutés après la création d'un flux filtré

Étant donné le code suivant:

List<String> strList = new ArrayList<>(Arrays.asList("Java","Python","Php"));

Stream<String> jFilter = strList.stream().filter(str -> str.startsWith("J"));

strList.add("JavaScript"); // element added after filter creation
strList.add("JQuery"); // element added after filter creation

System.out.println(Arrays.toString(jFilter.toArray())); 

qui produit:

[Java, JavaScript, JQuery]

Pourquoi JavaScript et JQuery apparaissent-ils dans le résultat filtré alors qu'ils ont été ajoutés après la création du flux filtré?

20
mmuzahid

Jusqu'à la déclaration 

System.out.println(Arrays.toString(jFilter.toArray()));

fonctionne, le flux ne fait rien. Une opération de terminal (toArray dans l'exemple) est requise pour que le flux soit traversé et que vos opérations intermédiaires (filter dans ce cas) soient exécutées.

Dans ce cas, vous pouvez, par exemple, capturer la taille de la liste avant d'ajouter d'autres éléments:

int maxSize = strList.size();
Stream<String> jFilter = strStream.limit(maxSize)
                                  .filter(str -> str.startsWith("J"));

limit(maxSize) ne permettra pas que plus que les éléments initiaux passent par le pipeline.

8
ernest_k

C'est parce que le flux n'a jamais été évalué. vous n'avez jamais appelé "Terminal operation" sur ce flux pour qu'il soit exécuté car lazy.

Regardez une modification de votre code et de la sortie. Le filtrage a effectivement lieu lorsque vous appelez l’opérateur du terminal.

 public static void main(String []args){
         List<String> strList = new ArrayList<>();
    strList.add("Java");
    strList.add("Python");
    strList.add("Php");

    Stream<String> strStream = strList.stream();

    Stream<String> jFilter = strStream.filter(str -> {
        System.out.println("Filtering" + str);
        return str.startsWith("J");
        });

 System.out.println("After Stream creation");
    strList.add("JavaScript"); // element added after filter creation
    strList.add("JQuery"); // element added after filter creation

    System.out.println(Arrays.toString(jFilter.toArray()));

     }

Sortie:

After Stream creation
FilteringJava
FilteringPython
FilteringPhp
FilteringJavaScript
FilteringJQuery
[Java, JavaScript, JQuery]
3
Bandi Kishore

Comme expliqué dans la documentation officielle à l'adresse https://docs.Oracle.com/javase/8/docs/api/Java/util/stream/package-summary.html , les flux ne disposent pas de stockage, de même que plus comme des itérateurs que des collections, et sont évalués paresseusement.

Donc, rien ne se passe vraiment en ce qui concerne le flux jusqu'à ce que vous appeliez l'opération de terminal toArray ()

1
GreyBeardedGeek

Le commentaire de @Hadi J mais il devrait être répondu selon les règles.

Parce que streams sont paresseux et lorsque vous appelez opération de terminal, il est exécuté.

1
user5377037

La méthode toArray est l'opération de terminal et elle fonctionne sur tout le contenu de votre liste. Pour obtenir un résultat prévisible, n'enregistrez pas la variable stream dans une variable temporaire, car cela entraînerait des résultats trompeurs. Un meilleur code est:

String[] arr = strList.stream().filter(str -> str.startsWith("J")).toArray();
0
fastcodejava