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 super T> 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.