Muchas veces cuando trabajamos con colecciones, generamos mucho código que resulta complicado de leer y entender, por lo tanto es costoso a la hora de mantenerlo.
Hoy vamos a ver Streams, que justamente viene a solucionarnos un poco la vida a la hora de usar colecciones.
¿Qué es un Stream?
Es un tanto difícil entender que es un stream, pero básicamente es una clase que nos permite usar operaciones funcionales sobre una colección de objetos. Pero no hay que confundirse un stream y una colección son muy diferentes, por ejemplo:
- Los streams no guardan ningún tipo de información, solo llevan datos de una fuente a través de varias operaciones.
- Una operación produce un resultado pero no modifica la fuente en sí.
- Las operaciones pueden ejecutarse de una manera “lazy”, por lo tanto se pueden optimizar en gran medida.
- No poseen un límite en la cantidad de elementos, por lo tanto puedo hacer operaciones sobre un stream infinito en tiempo finito.
Veamos un ejemplo para entender un poco mejor a los streams y como quedaría nuestro código.
List<String> pokemons = Arrays.asList("Zacian", "Grookey", "Scorbunny", "Sobble", "Zamazenta");
for (String pokemon : pokemons){
if(pokemon == "Scorbunny"){
System.out.println(pokemon);
}
}
Como vemos, realizar un filtrado en una colección se ve bastante complejo de entender y tendríamos que razonar lo que hace el código para saber que está filtrando.
List<String> pokemons = Arrays.asList("Zacian", "Grookey", "Scorbunny", "Sobble", "Zamazenta");
pokemons.stream()
.filter(pokemon -> pokemon == "Scorbunny")
.forEach(pokemonFiltrado -> System.out.println(pokemonFiltrado));
Con streams la cosa cambia, podemos ver claramente que filtra la colección fuente y obtenemos una nueva colección con los datos que deseamos.
Métodos útiles
Como vimos, los streams pueden hacer a nuestro código súper declarativo. Esto nos da la oportunidad de concentrarnos más en el “¿Que tengo que hacer?” y menos en el “¿Cómo tengo que hacerlo?”. Para eso, esta clase nos provee de varios métodos útiles que es mejor conocerlos.
Vamos a ver cómo se dividen en dos categorías, los métodos que se conectan para formar un proceso y los métodos que cierran el proceso.
Empecemos con los que se conectan para formar un proceso, estos son algunos de ellos:
- Filter: necesita un predicado y devuelve un stream con los elementos que coinciden con este.
- Map: recibe una función y nos permite proyectar los elementos del stream en otro formato.
- Distinct: nos devuelve un stream sin elementos repetidos.
- Sorted: este método puede o no recibir un argumento, y ordenará el stream (si no le pasamos un comparator los ordenará en su orden natural).
Ahora veamos a los de la otra categoría, los que finalizan un proceso:
- Collect: este método nos sirve para obtener el resultado de todas las operaciones hechas al stream.
- ForEach: nos permite iterar sobre cada elemento del stream.
- Reduce: este método es usado para reducir los elementos del stream a un solo valor, va a recibir por parámetro un operador binario.
Conclusión
Entonces, usar streams nos va a permitir manejar colecciones de una manera más clara y precisa. Esto se va a reflejar a la hora de mantener el código.
Si bien mencioné unos cuantos métodos, quiero que sepas que en este link podes encontrar información de todos los demás que no fueron mencionados.
Espero que a partir de hoy tu código pueda quedar impecable a la hora de manejar colecciones.