viernes, 5 de febrero de 2016

El nuevo Stream Api de Java 8

Seguiremos hablando sobre la versión 8 de Java, en conjunto con las expresiones Lambda, también se introduce el concepto de Streams, esta nueva característica ofrece comportamientos similares a los iteradores que todos conocemos pero con un enfoque distinto. Los Streams son objetos de clases que implementan la interfaz Stream (desde el paquete java.util.stream) o una de las interfaces especializadas Stream enfocadas en el procesamiento de colecciones de valores int, long o double.

Antes de proseguir recomiendo a todos los que no estén del todo familiarizados con las Expresiones Lambda que se detengan en este punto y lean primero el artículo donde hablamos sobre este tema

Tuberías Stream

Los Streams mueven los elementos a través de una secuencia de pasos de procesamiento llamados tuberías Stream o Stream Pipelines (como se les nombra en Inglés) y que comienzan con una fuente de datos que puede ser tanto un arreglo o una colección, ejecutando sobre estos operaciones intermedias, finalizando evidentemente con una operación final. Una tubería Stream se forma encadenando llamadas a métodos y a diferencia de las colecciones estas no cuentan con almacenamiento propio, por esto es que un Stream, una vez utilizada, no se puede volver a usar debido a que esta no mantiene una copia de los datos originales.

Operaciones Intermedias y Finales

Una operación intermedia aplica una tarea específica sobre el elemento actual del flujo de datos, dando como resultado un nuevo flujo ya modificado. Se dice que las operaciones intermedias son lazy (perezosas) ya que estas no comienzan su cadena de ejecución hasta que la operación final es invocada.

Por ejemplo si usted tiene una colección de 1,000,000 objetos Persona y deseamos encontrar el primero de estos cuyo primer apellido sea Bergery, el flujo de procesamiento puede terminar tan pronto como sea encontrada la primera coincidencia.

Una operación final comienza procesando la cadena de operaciones intermedias especificadas por nosotros finalizando con un resultado, que teniendo en cuenta el ejemplo anterior este sería un solo objeto del total inicial. Este comportamiento le da el nombre de eager (ansioso) que sería lo contrario de lazy (perezoso) en comparación a las operaciones intermedias, estos ejecutan las operaciones requeridas al momento de ser invocados.

Operaciones intermedias más com

filter, distinct, limit, map, sorted



Operaciones finales más comunes:

forEach, average, count, max, min, reduce, collect, toArray, findFirst, findAny, anyMatch, allMatch



Vamos a ver un ejemplo donde vemos en acción todas estas operaciones:

package com.wiseratel;
 
import java.util.stream.IntStream;
 
public class StreamAPI {
 
    public static void main(String[] args) {
 
        int[] values = {3, 10, 6, 1, 4, 8, 2, 5, 9, 7};
 
        // Mostrar los valores originales
 
        System.out.println("Valores originales: ");
 
        IntStream.of(values).forEach(value -> System.out.printf("%d ", value));
 
        System.out.println();
 
        // Ejecución de las funciones count, min, max, sum y average sobre los valores
 
        System.out.printf("%nCount: %d%n", IntStream.of(values).count());
 
        System.out.printf("Min: %d%n", IntStream.of(values).min().getAsInt());
 
        System.out.printf("Max: %d%n", IntStream.of(values).max().getAsInt());
 
        System.out.printf("Sum: %d%n", IntStream.of(values).sum());
 
        System.out.printf("Average: %.2f%n", IntStream.of(values).average().getAsDouble());
 
        // Suma de los valores con el método reduce
 
        System.out.printf("%nSuma usando el método reduce: %d%n", IntStream.of(values).reduce(0, (x, y) -> x + y));
 
        // Suma de los cuadrados de los valores usando el método reduce
 
        System.out.printf("Suma de los cuadrados usando el método reduce: %d%n", IntStream.of(values).reduce(0, (x, y) -> x + y * y));
 
        // Producto de los valores usando el método reduce
 
        System.out.printf("Productos usando el método reduce: %d%n", IntStream.of(values).reduce(1, (x, y) -> x * y));
 
        // Números pares mostrados de manera ordenada
 
        System.out.println();
 
        System.out.println("Números pares mostrados de manera ordenada: ");
 
        IntStream.of(values).filter(value -> value % 2 == 0).sorted().forEach(value -> System.out.printf("%d ", value));
 
        System.out.println();
 
        System.out.println("Números impares multiplicados por 10 y mostrados de manera ordenada: ");
 
        IntStream.of(values).filter(value -> value % 2 != 0).map(value -> value * 10).sorted().forEach(value -> System.out.printf("%d ", value));
 
        System.out.println();
 
        // Suma los valores del 1 al 10, exclusivo
 
        System.out.printf("%nSuma los valores del 1 al 9, exclusivo: %d%n", IntStream.range(1, 10).sum());
 
        // Suma los valores del 1 al 10, inclusivo
 
        System.out.printf("Suma los valores del 1 al 10, inclusivo: %d%n", IntStream.rangeClosed(1, 10).sum());
 
    } // main
 
} // StreamAPI



Esta seria la salida en pantalla:

3 10 6 1 4 8 2 5 9 7 
 
Count: 10
Min: 1
Max: 10
Sum: 55
Average: 5.50
 
Suma usando el método reduce: 55
Suma de los cuadrados usando el método reduce: 385
Productos usando el método reduce: 3628800
 
Números pares mostrados de manera ordenada: 
2 4 6 8 10 
Números impares multiplicados por 10 y mostrados de manera ordenada: 
10 30 50 70 90 
 
Suma los valores del 1 al 9, exclusivo: 45
Suma los valores del 1 al 10, inclusivo: 55

No hay comentarios.:

Publicar un comentario