Streams con filter() en Java


En este tutorial vamos a ver ejemplos de streams con filter() en diferentes usos como collect(), findAny(), anyMatch() y map(), todo ello gracias a los streams de Java. En una entrada anterior, ya se pudo ver como realizar transformaciones con un HashMap.

Los Streams fueron introducidos con Java 8, en los siguientes ejemplos veremos como se haría antes de tener Java 8 y como lo haríamos usando streams.

Uso de filter() y collect() con streams

En el siguiente ejemplo vamos a escribir, el coche que sea de color azul:

Filtro sin Streams

package com.refactorizando.streams;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class BeforeStreams {

    public static void main(String[] args) {

        List<String> colorCars = Arrays.asList("blue", "red", "green");
        List<String> colors = getColorBlue(colorCars);
        for (String color : colors) {
            System.out.println(color);    
        }

    }

    private static List<String> getColorBlue(List<String> colorCars) {
        List<String> colors = new ArrayList<>();
        for (String color : colorCars) {
            if ("blue".equals(color)) { 
                colors.add(color);
            }
        }
        return colors;
    }

}

Salida:

blue

Streams con filter() de Java

package com.refactorizando.streams;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class WithStreams {

    public static void main(String[] args) {

       List<String> colorCars = Arrays.asList("blue", "red", "green");

        List<String> colorBlue = colorCars.stream()               
                .filter(color -> "blue".equals(color))     
                .collect(Collectors.toList());             

        result.forEach(System.out::println);               

    }

}

Salida:

blue

En el ejemplo anterior hemos visto como recorremos una lista haciendo uso de stream, para obtener el color azul.

Uso de findAny() y findFirst()

Para el siguiente ejemplo vamos a seguir buscando el color azul en un coche, pero vamos a tener varios coches y varios colores azules.

Para ello primero nos definimos el objeto coche.

package com.refactorizando.streams;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Car {

    private String model;
    private String color;

   public List<Car> createCars() {
     return Arrays.asList(
                new Car("Mazda", "Red"),
                new Car("Seat", "Blue"),
                new Car("Audi", "Blue")
        );
   }

}

Filtro sin Streams

En este caso vamos a encontrar cualquier coche que tenga color azul.

package com.refactorizando.streams;

import java.util.Arrays;
import java.util.List;

public class BeforeStreams {

    public static void main(String[] args) {
     
        Car car = new Car();
        List<Car> cars =  car.createCars();

        Car carResult = getBlueCars(cars);

        System.out.println(carResult);

    }

    private static Car getBlueCars(List<Car> cars) {

        Car car = null;
        
        for (Car c : cars) {
            if ("blue".equalsIgnoreCase(c.getColor())) {
                car = c;
            }
        }
        return car;
    }
}

Salida

Car{model='Audi', color='Blue'}

Streams con filter() y findAny()

Con findAny() encontraremos cualquier coche que tenga el color azul, una vez que pasa el filtro.

package com.refactorizando.streams;

import java.util.Arrays;
import java.util.List;

public class WithStreams {

    public static void main(String[] args) {

        Car car = new Car();
        List<Car> cars =  car.createCars();

        Optional<Car> colorCar = cars.stream()                        
                .filter(c -> "blue".equalsIgnoreCase(c.getColor()))       
                .findAny();                                  
        //Al devolver un optional sacamos el valor
        System.out.println(colorCar.orElseThrow());

    }

}

Salida

Car{model='Audi', color='Blue'}

Streams con filter() y findFirst()

La diferencia entre findFirst() y findAny() es que con el primero encontraremos el primer valor que cumpla el filtro, y con el segundo cualquier valor.

package com.refactorizando.streams;

import java.util.Arrays;
import java.util.List;

public class WithStreams {

    public static void main(String[] args) {

        Car car = new Car();
        List<Car> cars =  car.createCars();

        Optional<Car> colorCar = cars.stream()                        
                .filter(c -> "blue".equalsIgnoreCase(c.getColor()))       
                .findFirst();                                  

        //Al devolver un optional sacamos el valor
        System.out.println(colorCar.orElseThrow());

    }

}

Salida:

Car{model='Seat', color='Blue'}

Streams con filter(), Map() y findAny()

Map dentro de un stream de Java nos da la posibilidad de convertir un tipo de objeto en otro, o trabajar con el objeto que hemos recibido, lo más fácil es ver un ejemplo:

package com.refactorizando.streams;

import java.util.Arrays;
import java.util.List;

public class WithStreamsMap {

    public static void main(String[] args) {

        Car car = new Car();
        List<Car> cars =  car.createCars();

        String modelCar = cars.stream()                        
                .filter(c -> "blue".equalsIgnoreCase(c.getColor()))
                .map(Car::getModel)       
                .findAny() //si utilizamos findFirst() obtenemos el primero
                .orElseThrow()                                  

        //Lanzamos una excepción si no existe ningún valor.
        System.out.println(modelCar);
       
       List<String> carsByColorBlue = cars.stream()
                   .filter(c->"blue".equalsIgnoreCase(c.getColor()))
                   .map(Car::getModel)
                   .collect(Collectors.toList());
      //Convertirmos en una lista de modelos el array inicial
      carsByColorBlue.forEach(System.out::println);
    }

}

Salida modelCar:

Audi

Salida carsByColorBlue:

Seat
Audi

Debug y logging de Streams

En muchas ocasiones cuando nos encontramos trabajando con Streams de Java nos surge la duda de como podemos hacer logging o hacer debug sobre ese stream. Para estos casos, la mejor manera y la que nos proporciona el API de Streams es mediante el uso de Peek.

Hay que tener en cuenta que el uso de Peek es como operación intermedia únicamente. Y lo que la documentación oficial nos dice, es que su uso es exclusivo de debug, por lo que cualquier otra aproximación se desaconseja.

Stream.of("apple", "orange", "cherry", "banana")
  .filter(e -> e.length() > 6)
  .peek(e -> System.out.println("Fruits are : " + e))
  .map(String::toUpperCase)
  .peek(e -> System.out.println("Now are upperCase " + e))
  .collect(Collectors.toList());

Aunque podríamos lograr lo mismo con map y peek, el objetivo de peek es únicamente para debug en nuestros streams.

Conclusión

En esta entrada hemos visto como funciona filter() en streams con java y algún ejemplo para poder procesar el stream, como findFirst(), findAny() y map(), pero si quieres profundizar algo más, vendría bien echar un ojo al siguiente tutorial: https://www.oracle.com/technetwork/es/articles/java/procesamiento-streams-java-se-8-2763402-esa.html


Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *