La definición de flujo en Java 8 es «una secuencia de elementos de una fuente que admite operaciones agregadas». Los flujos consumen desde una fuente como colecciones, matrices o recursos de E / S. Los flujos admiten las operaciones comunes de los lenguajes de programación funcionales, como mapear, filtrar, reducir, buscar, ordenar, etc.
Un ejemplo motivacional
Es fácil encadenar varios métodos que aceptan la expresión lambda como parámetro. Un cálculo complejo antes de Java 8 se puede escribir en muchas menos líneas.
Aquí hay un muy buen ejemplo motivacional de Java doc.[1]:
int sum = components.stream() .filter(c -> c.getColor() == RED) .mapToInt(c -> c.getWeight()) .sum(); |
En este ejemplo usamos componentes, una colección
Transmisión frente a colección
Las corrientes pueden parecer similares a las colecciones, pero son conceptos muy diferentes. Cuando trabaja con grandes conjuntos de datos, es posible que no desee procesar todo el conjunto de datos como una colección. Hay una metáfora muy buena al comparar la diferencia entre Colección y Stream. [5]. Considere una película almacenada en un DVD en lugar de transmitida a través de Internet. Una película se puede ver como un conjunto de bytes. El DVD se puede ver como una colección de bytes porque contiene todos los elementos de datos. Al ver la película a través de Internet, la película se puede ver como un flujo de bytes. El reproductor de transmisión de video solo necesita tener unos pocos bytes antes de donde el usuario está mirando. De esta manera, el reproductor de video puede comenzar a mostrar la película desde el principio de la transmisión antes de que la mayoría de los datos de la transmisión se hayan calculado siquiera.
La diferencia entre Stream y Collection se puede detallar de la siguiente manera:
- Una secuencia proporciona una interfaz para un conjunto secuenciado de valores de un tipo de elemento específico. Sin embargo, a diferencia de las colecciones, las transmisiones en realidad no almacenan elementos. Los elementos se calculan bajo demanda. Los flujos se pueden ver como colecciones construidas de forma perezosa, cuyos valores se calculan cuando se necesitan.
- Las operaciones de transmisión no cambian su fuente. En cambio, devuelven nuevos flujos que almacenan el resultado.
- Posiblemente ilimitado. Las colecciones tienen un tamaño finito, pero las transmisiones no. Las operaciones de cortocircuito como limit (n) o findFirst () pueden permitir que los cálculos en flujos infinitos se completen en un tiempo finito.
- Consumible. Durante la vida útil de una transmisión, los elementos de la transmisión solo se visitan una vez. Si desea volver a visitar el mismo elemento en la transmisión, deberá volver a generar una nueva transmisión en función de la fuente.
Operaciones intermedias frente a operaciones de terminal
Las operaciones intermedias transforman un flujo en otro, mientras que las operaciones terminales producen un resultado. Cuando se ejecuta una operación de terminal en una secuencia, la secuencia ya no se puede utilizar.
Por ejemplo, en el siguiente código:
list.stream().filter(s -> s.length() > 2).count(); |
filter () es una operación intermedia y count () es una operación terminal. Cuando se llama a count (), ya no podemos usar la secuencia.
Las operaciones intermedias de uso frecuente incluyen: filtro, mapa, diferenciado, ordenado, salto, límite, mapa plano
Las operaciones de la terminal de uso frecuente incluyen:
- forEach, toArray, recopilar, reducir, contar, min, max
- findFirst, findAny, anyMatch, allMatch, noneMatch
Referencias:
1. Documento Java de Stream
2. Mónada en programación funcional
3. Procesamiento de datos con secuencias de Java SE 8, parte 1
4. paquete java.util.stream
5. Java 8 Lambdas en acción, por Raoul-Gabriel Urma, Mario Fusco y Alan Mycroft