Vamos a continuar la serie que iniciamos hace unas semanas con el post “Java 8 – Expresiones Lambda”. En aquel post os hablábamos sobre las Expresiones Lambda e Interfaces Funcionales. En esta ocasión, vamos a aprovechar el conocimiento adquirido en aquel post para hablaros de cómo tratar las colecciones en Java de una manera nueva, usando Streams.
Los Streams en java son un nuevo modelo de datos que nos permite tratar las colecciones como si de etapas de un proceso ETL (“Extract Transform and Load”) se tratara. Esto nos permite utilizar las funciones Map y Reduce tan comunes en esos procesos, especialmente en la etapa de transformación.
En java 8, toda colección tiene un método stream() que transformará dicha estructura en Stream. Por ejemplo vamos a crear una instancia llamada “streangs” de Stream de Strings.
[java] List<String> strings = …;Stream<String> streangs = strings.stream();
[/java]
Algunas de las funciones más significativas de esta nueva clase serían:
Foreach: Aplica una función a cada uno de los elementos. Este método es terminal, no se puede encadenar con otra etapa del Stream.
[java] streangs.forEach(s -> System.out.println(s)); // expresión Lambdastreangs.forEach(System.out::println); // referencia a función
// Imprime por pantalla cada una de las cadenas [/java]
Map: Transforma cada uno de los objetos que contiene la colección, pudiendo incluso cambiar el tipo de Stream.
[java] streangs.map(s -> s + "_MAPPED");// Añadiría la cadena "_MAPPED" a todos los elementos
streangs.map(s -> Integer.parse(s));
// Transforma cada elemento en un Integer
// A partir de aquí el Stream<String> cambie a Stream<Integer>
Reduce: Transforma la colección en único objeto del mismo tipo después de aplicar una función de agregación a cada elemento.
[java] streangs.reduce("", // Valor inicial(s1, s2) -> s1 + " " + s2); // Concatena cada elemento con el agregado
// Con esto obtendríamos una única cadena concatenando todos sus elementos [/java]
Filter: Filtra los elementos que satisfagan una determinada condición.
[java] streangs.filter(s -> s.length() > 5); // Solo mantenemos cadenas de longitud mayor a 5 [/java]Collect: El paso final de la transformación del Stream, nos permitirá por ejemplo volverlo a convertir a una lista estándar.
[java] List<String> result = streangs.collect(Collectors.toList()); [/java]Salvo los métodos finales como son collect, reduce o forEach todos se pueden ir encadenando como si fueran tuberías, creando un proceso de transformación más complejo.
[java]// Obtenemos las cadenas ordenadas que representen números paresList<String> even = strings.stream()
.map(string -> Integer.valueOf(s))
.filter(integer -> integer % 2 == 0)
.distinct()
.sorted()
.map(integer::toString)
.collect(Collectors.toList()); [/java]
A modo de conclusión, podemos decir que con estos streams tenemos una nueva manera de procesar colecciones de datos respecto a las tradicionales sentencias de control como pueden ser bucles y condiciones. Además, también nos proporcionan la ventaja de poder “exprimir” más a los procesadores, utilizando para ello los parallelStream, que utilizan varios hilos de ejecución en cada etapa de procesamiento.
Leave a Reply