parallel instream funciones ejemplo collection colecciones java java-8 java-stream

java - instream - Teniendo en cuenta los elementos de lista que se agregan después de la creación de secuencias filtradas



stream parallel java 8 (6)

Respuesta corta

Estás asumiendo después de este punto:

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

Que se devuelva una nueva secuencia de los elementos que comienzan con "J", es decir, solo Java . Sin embargo, este no es el caso;

los flujos son perezosos, es decir, no realizan ninguna lógica a menos que se indique lo contrario por una operación de terminal.

La ejecución real de la toArray() del flujo comienza en la llamada toArray() y como la lista se modificó antes de que la toArray() terminal toArray() comenzara, el resultado será [Java, JavaScript, JQuery] .

Respuesta más larga

Aquí hay una parte de la documentation que menciona esto:

Para fuentes de flujo de buen comportamiento, la fuente se puede modificar antes de que comience la operación del terminal y esas modificaciones se reflejarán en los elementos cubiertos. Por ejemplo, considere el siguiente código:

List<String> l = new ArrayList(Arrays.asList("one", "two")); Stream<String> sl = l.stream(); l.add("three"); String s = sl.collect(joining(" "));

Primero se crea una lista que consta de dos cadenas: "uno"; y dos". Entonces se crea una secuencia de esa lista. A continuación, la lista se modifica agregando una tercera cadena: "tres". Finalmente los elementos de la corriente se recogen y se unen. Dado que la lista se modificó antes de que comenzara la operación de recolección del terminal, el resultado será una cadena de "uno dos tres". Todas las secuencias devueltas de las colecciones JDK, y la mayoría de las otras clases de JDK, se comportan de esta manera;

Dado el siguiente código:

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

que produce:

[Java, JavaScript, JQuery]

¿Por qué aparecen JavaScript y JQuery en el resultado filtrado aunque se agregaron después de crear el flujo filtrado?


Como se explica en la documentación oficial en documentation , los flujos no tienen almacenamiento, y por lo tanto son más parecidos a iteradores que Las colecciones, y son evaluadas perezosamente.

Entonces, nada sucede realmente con respecto al flujo hasta que invoque la operación del terminal toArray ()


El comentario de @Hadi J, pero debería ser respondido de acuerdo a las reglas.

Debido a que los streams son perezosos y cuando se llama a la operación de terminal, se ejecuta.


El método toArray es la operación del terminal y funciona en ese contenido completo de su lista. Para obtener un resultado predecible, no guarde la stream en una variable temporal, ya que dará lugar a resultados confusos. Un mejor código es:

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


Es porque la corriente nunca fue evaluada. nunca llamó a una " Operación de terminal " en ese flujo para que se ejecute ya que son perezosos .

Mira una modificación de tu código y la salida. El filtrado en realidad tiene lugar cuando llama al operador de 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())); }

Salida:

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


Hasta la declaración

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

corre, la corriente no hace nada. Se toArray una operación de terminal ( toArray en el ejemplo) para que la corriente sea atravesada y sus operaciones intermedias ( filter en este caso) para ser ejecutadas.

En este caso, lo que puede hacer es, por ejemplo, capturar el tamaño de la lista antes de agregar otros elementos:

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

donde limit(maxSize) no permitirá que más de los elementos iniciales pasen por la tubería.