Filtro de fluxo Java com expressão lambda

Filtro de fluxo Java com expressão lambda

1. Introdução

Neste tutorial rápido, vamos explorar o uso do métodoStream.filter() quando trabalhamos comStreams in Java.

Mostraremos como usá-lo e como lidar com casos especiais com exceções verificadas.

2. UsandoStream.filter()

O métodofilter() é uma operação intermediária da interfaceStream que nos permite filtrar os elementos de um fluxo que correspondem a um determinadoPredicate:

Stream filter(Predicate predicate)

Para ver como isso funciona, vamos criar uma classeCustomer:

public class Customer {
    private String name;
    private int points;
    //Constructor and standard getters
}

Além disso, vamos criar uma coleção de clientes:

Customer john = new Customer("John P.", 15);
Customer sarah = new Customer("Sarah M.", 200);
Customer charles = new Customer("Charles B.", 150);
Customer mary = new Customer("Mary T.", 1);

List customers = Arrays.asList(john, sarah, charles, mary);

2.1. Filtrando coleções

Um caso de uso comum do métodofilter() éprocessing collections.

Vamos fazer uma lista de clientes com mais de 100points.. Para fazer isso, podemos usar uma expressão lambda:

List customersWithMoreThan100Points = customers
  .stream()
  .filter(c -> c.getPoints() > 100)
  .collect(Collectors.toList());

Também podemos usarmethod reference, que é uma abreviação para uma expressão lambda:

List customersWithMoreThan100Points = customers
  .stream()
  .filter(Customer::hasOverHundredPoints)
  .collect(Collectors.toList());

Mas, para este caso, adicionamos o métodohasOverHundredPoints à nossa classeCustomer:

public boolean hasOverHundredPoints() {
    return this.points > 100;
}

Nos dois casos, obtemos o mesmo resultado:

assertThat(customersWithMoreThan100Points).hasSize(2);
assertThat(customersWithMoreThan100Points).contains(sarah, charles);

2.2. Filtrando coleções com múltiplos critérios

Além disso, podemos usar várias condições comfilter(). Por exemplo, filtre porpoints ename:

List charlesWithMoreThan100Points = customers
  .stream()
  .filter(c -> c.getPoints() > 100 && c.getName().startsWith("Charles"))
  .collect(Collectors.toList());

assertThat(charlesWithMoreThan100Points).hasSize(1);
assertThat(charlesWithMoreThan100Points).contains(charles);

3. Tratamento de exceções

Até agora, temos usado o filtro com predicados que não lançam uma exceção. Na verdade, ofunctional interfaces in Java don’t declare any checked or unchecked exception.

A seguir, mostraremos algumas maneiras diferentes de lidar comexceptions in lambda expressions.

3.1. Usando um Wrapper Personalizado

Primeiro, vamos começar a adicionar ao nossoCustomer aprofilePhotoUrl:

private String profilePhotoUrl;

Além disso, vamos adicionar um métodohasValidProfilePhoto() simples para verificar a disponibilidade do perfil:

public boolean hasValidProfilePhoto() throws IOException {
    URL url = new URL(this.profilePhotoUrl);
    HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
    return connection.getResponseCode() == HttpURLConnection.HTTP_OK;
}

Podemos ver que o métodohasValidProfilePhoto() lança umIOException. Agora, se tentarmos filtrar os clientes com este método:

List customersWithValidProfilePhoto = customers
  .stream()
  .filter(Customer::hasValidProfilePhoto)
  .collect(Collectors.toList());

Veremos o seguinte erro:

Incompatible thrown types java.io.IOException in functional expression

Para lidar com isso, uma das alternativas que podemos usar é envolvê-lo com um bloco try-catch:

List customersWithValidProfilePhoto = customers
  .stream()
  .filter(c -> {
      try {
          return c.hasValidProfilePhoto();
      } catch (IOException e) {
          //handle exception
      }
      return false;
  })
  .collect(Collectors.toList());

Se precisarmos lançar uma exceção de nosso predicado, podemos envolvê-la em uma exceção não verificada comoRuntimeException.

3.2. UsandoThrowingFunction

Como alternativa, podemos usar a bibliotecaThrowingFunction.

ThrowingFunction é uma biblioteca de código aberto que permite lidar com exceções verificadas nas interfaces funcionais Java.

Vamos começar adicionandothrowing-function dependency ao nosso pom:


    pl.touk
    throwing-function
    1.3

Para lidar com exceções em predicados, esta biblioteca nos oferece a classeThrowingPredicate, que possui o métodounchecked() para quebrar exceções verificadas.

Vamos ver em ação:

List customersWithValidProfilePhoto = customers
  .stream()
  .filter(ThrowingPredicate.unchecked(Customer::hasValidProfilePhoto))
  .collect(Collectors.toList());

4. Conclusão

Neste artigo, vimos um exemplo de como usar o métodofilter() para processar fluxos. Além disso, exploramos algumas alternativas para lidar com exceções.

Como sempre, o código completo está disponívelover on GitHub.