DistinctBy na API Java Stream
1. Visão geral
Procurar elementos diferentes em uma lista é uma das tarefas comuns que nós, como programadores, geralmente enfrentamos. A partir do Java 8 com a inclusão deStreams, temos uma nova API para processar dados usando abordagem funcional.
Neste artigo, mostraremos diferentes alternativas para filtrar uma coleção usando um atributo específico de objetos na lista.
2. Usando a API de Stream
A API Stream fornece o métododistinct() que retorna diferentes elementos de uma lista com base no métodoequals() da classeObject.
No entanto, torna-se menos flexível se quisermos filtrar por um atributo específico. Uma das alternativas que temos é escrever um filtro que mantenha o estado.
2.1. Usando um Filtro Stateful
Uma das soluções possíveis seria implementar umPredicate: com estado
public static Predicate distinctByKey(
Function super T, ?> keyExtractor) {
Map
Para testá-lo, usaremos a seguinte classePerson que tem os atributosage,email ename:
public class Person {
private int age;
private String name;
private String email;
// standard getters and setters
}
E para obter uma nova coleção filtrada porname, podemos usar:
List personListFiltered = personList.stream()
.filter(distinctByKey(p -> p.getName()))
.collect(Collectors.toList());
3. Usando coleções Eclipse
Eclipse Collections é uma biblioteca que fornece métodos adicionais para processarStreamse coleções em Java.
3.1. Usando oListIterate.distinct()
O métodoListIterate.distinct() nos permite filtrar umStream usando váriosHashingStrategies.. Essas estratégias podem ser definidas usando expressões lambda ou referências de método.
Se quisermos filtrar pelo nomePerson’s:
List personListFiltered = ListIterate
.distinct(personList, HashingStrategies.fromFunction(Person::getName));
Ou, se o atributo que vamos usar for primitivo (int, long, double), podemos usar uma função especializada como esta:
List personListFiltered = ListIterate.distinct(
personList, HashingStrategies.fromIntFunction(Person::getAge));
3.2. Dependência do Maven
Precisamos adicionar as seguintes dependências ao nossopom.xml para usar coleções Eclipse em nosso projeto:
org.eclipse.collections
eclipse-collections
8.2.0
Você pode encontrar a versão mais recente da biblioteca Eclipse Collections no repositórioMaven Central.
Para aprender mais sobre esta biblioteca, podemos ir parathis article.
4. Using Vavr (Javaslang *) *
Esta é uma biblioteca funcional para Java 8 que fornece dados imutáveis e estruturas de controle funcional.
4.1. UsandoList.distinctBy
Para filtrar listas, esta classe fornece sua própria classe List que possui o métododistinctBy() que nos permite filtrar por atributos dos objetos que ela contém:
List personListFiltered = List.ofAll(personList)
.distinctBy(Person::getName)
.toJavaList();
4.2. Dependência do Maven
Adicionaremos as seguintes dependências ao nossopom.xml para usar o Vavr em nosso projeto.
io.vavr
vavr
0.9.0
Você pode encontrar a versão mais recente da biblioteca Vavr no repositórioMaven Central.
Para aprender mais sobre esta biblioteca, podemos ir parathis article.
5. Usando StreamEx
Esta biblioteca fornece classes e métodos úteis para o processamento de fluxos Java 8.
5.1. UsandoStreamEx.distinct
Dentro das classes fornecidas estáStreamEx que tem o métododistinct para o qual podemos enviar uma referência ao atributo onde queremos distinguir:
List personListFiltered = StreamEx.of(personList)
.distinct(Person::getName)
.toList();
5.2. Dependência do Maven
Adicionaremos as seguintes dependências ao nossopom.xml para usar o StreamEx em nosso projeto.
one.util
streamex
0.6.5
Você pode encontrar a versão mais recente da biblioteca StreamEx no repositórioMaven Central.
6. Conclusão
Neste tutorial rápido, exploramos exemplos de como obter elementos diferentes de um Stream, com base em um atributo usando a API Java 8 padrão e alternativas adicionais com outras bibliotecas.
Como sempre, o código completo está disponívelover on GitHub.