Como filtrar uma coleção em Java
1. Visão geral
Neste breve tutorial,we’ll have a look at different ways of filtering a Collection in Java - ou seja, encontrar todos os itens que atendem a uma determinada condição.
Essa é uma tarefa fundamental que está presente em praticamente qualquer aplicativo Java.
Por esse motivo, o número de bibliotecas que fornecem funcionalidade para esse fim é significativo.
Particularmente, neste tutorial, cobriremos:
-
Funçãofilter() do Java 8 Streams
-
Coletor Java 9filtering
-
APIsEclipse Collections relevantes
-
MétodoCollectionUtils filter() do Apache
-
Abordagem deCollections2 filter() da Goiaba
2. Usando fluxos
Desde que o Java 8 foi introduzido,Streams ganhou um papel fundamental na maioria dos casos em que precisamos processar uma coleção de dados.
Consequentemente, essa é a abordagem preferida na maioria dos casos, pois é construída em Java e não requer dependências adicionais.
2.1. Filtrando uma coleção comStreams
Para simplificar,in all the examples our objective will be to create a method that retrieves only the even numbers from a Collection dos valoresInteger.
Assim, podemos expressar a condição que usaremos para avaliar cada item como ‘value % 2 == 0’.
Em todos os casos, teremos que definir esta condição como um objetoPredicate:
public Collection findEvenNumbers(Collection baseCollection) {
Predicate streamsPredicate = item -> item % 2 == 0;
return baseCollection.stream()
.filter(streamsPredicate)
.collect(Collectors.toList());
}
É importante notar queeach library we analyze in this tutorial provides its own Predicate implementation, mas ainda assim, todos eles são definidos como interfaces funcionais, portanto, nos permitindo usar funções Lambda para declará-los.
Neste caso, usamos umCollector predefinido fornecido por Java que acumula os elementos emList, mas poderíamos ter usado outros, conforme discutido emthis previous post.
2.2. Filtrando após agrupar uma coleção em Java 9
Os fluxos nos permitem agregar itens usandogroupingBy collector.
No entanto, se filtrarmos como fizemos na última seção, alguns elementos poderão ser descartados em um estágio inicial, antes que esse colecionador entre em ação.
Por este motivo,the filtering collector was introduced with Java 9, with the objective of processing the subcollections after they have been grouped.
Seguindo nosso exemplo, vamos imaginar que queremos agrupar nossa coleção com base no número de dígitos que cada Inteiro possui, antes de filtrar os números ímpares:
public Map> findEvenNumbersAfterGrouping(
Collection baseCollection) {
Function getQuantityOfDigits = item -> (int) Math.log10(item) + 1;
return baseCollection.stream()
.collect(groupingBy(
getQuantityOfDigits,
filtering(item -> item % 2 == 0, toList())));
}
Em suma, se usarmos esse coletor, podemos acabar com uma entrada de valor vazia, ao passo que, se filtrarmos antes de agrupar, o coletor não criará tal entrada.
Obviamente, escolheríamos a abordagem com base em nossos requisitos.
3. UsandoEclipse Collections
Também podemos fazer uso de algumas outras bibliotecas de terceiros para cumprir nosso objetivo, seja porque nosso aplicativo não oferece suporte a Java 8 ou porque queremos tirar proveito de algumas funcionalidades poderosas não fornecidas pelo Java.
É o caso deEclipse Collections, uma biblioteca que se esforça para acompanhar os novos paradigmas, evoluindo e abraçando as mudanças introduzidas por todos os últimos lançamentos Java.
Podemos começar explorando nossoEclipse Collections Introductory post para ter um conhecimento mais amplo da funcionalidade fornecida por esta biblioteca.
3.1. Dependências
Vamos começar adicionando a seguinte dependência aopom.xml do nosso projeto:
org.eclipse.collections
eclipse-collections
9.2.0
Oeclipse-collections inclui todas as interfaces de estrutura de dados necessárias e a própria API.
3.2. Filtrando uma coleção comEclipse Collections
Vamos agora usar a funcionalidade de filtragem do eclipse em uma de suas estruturas de dados, comoMutableList:
public Collection findEvenNumbers(Collection baseCollection) {
Predicate eclipsePredicate
= item -> item % 2 == 0;
Collection filteredList = Lists.mutable
.ofAll(baseCollection)
.select(eclipsePredicate);
return filteredList;
}
Como alternativa, poderíamos ter usado o métodoIterate'sselect() static para definir o objetofilteredList:
Collection filteredList
= Iterate.select(baseCollection, eclipsePredicate);
4. UsandoCollectionUtils do Apache
Para começar com a bibliotecaCollectionUtils do Apache, podemos verificarthis short tutorial onde cobrimos seus usos.
Neste tutorial, no entanto, vamos nos concentrar em sua implementação de filter().
4.1. Dependências
Primeiro, precisaremos das seguintes dependências em nosso arquivopom.xml:
org.apache.commons
commons-collections4
4.2
4.2. Filtrando uma coleção comCollectionUtils
Agora estamos prontos para usar os métodosCollectonUtils ':
public Collection findEvenNumbers(Collection baseCollection) {
Predicate apachePredicate = item -> item % 2 == 0;
CollectionUtils.filter(baseCollection, apachePredicate);
return baseCollection;
}
Temos que levar em consideração que este método modifica obaseCollection removendo todos os itens que não correspondem à condição.
Isso significa quethe base Collection has to be mutable, otherwise it will throw an exception.
5. UsandoCollections2 de Guava
Como antes, podemos ler nosso post anterior‘Filtering and Transforming Collections in Guava' para mais informações sobre este assunto.
5.1. Dependências
Vamos começar adicionandothis dependency em nosso arquivopom.xml:
com.google.guava
guava
25.1-jre
5.2. Filtrando uma coleção comCollections2
Como podemos ver, essa abordagem é bastante semelhante à seguida na última seção:
public Collection findEvenNumbers(Collection baseCollection) {
Predicate guavaPredicate = item -> item % 2 == 0;
return Collections2.filter(baseCollection, guavaPredicate);
}
Novamente, aqui definimos um objetoPredicate específico do Guava.
Neste caso, o Guava não modifica obaseCollection, ele gera um novo, então podemos usar uma coleção imutável como entrada.
6. Conclusão
Em resumo, vimos que existem muitas maneiras diferentes de filtrar coleções em Java.
Embora o Streams seja geralmente a abordagem preferida, é bom conhecer e ter em mente a funcionalidade oferecida por outras bibliotecas.
Especialmente se precisarmos suportar versões Java mais antigas. No entanto, se esse for o caso, precisamos ter em mente que os recursos Java recentes usados em todo o tutorial, como lambdas, devem ser substituídos por classes anônimas.
Como de costume, podemos encontrar todos os exemplos mostrados neste tutorial em nossoGithub repo.