Articles

filtrar uma coleção Java por uma lista

visão geral

filtrar uma coleção por uma lista é um cenário lógico de negócios comum. Há muitas formas de o conseguir. No entanto, alguns podem levar a soluções com baixo desempenho se não for feito corretamente.

neste tutorial, vamos comparar algumas implementações de filtragem e discutir as suas vantagens e desvantagens.

usando um para-cada ciclo

vamos começar com a sintaxe mais clássica, um para-cada ciclo.

Para este e todos os outros exemplos neste artigo, vamos utilizar a classe a seguir:

public class Employee { private Integer employeeNumber; private String name; private Integer departmentId; //Standard constructor, getters and setters.}

vamos também usar os seguintes métodos para todos os exemplos, para fins de simplicidade:

private List<Employee> buildEmployeeList() { return Arrays.asList( new Employee(1, "Mike", 1), new Employee(2, "John", 1), new Employee(3, "Mary", 1), new Employee(4, "Joe", 2), new Employee(5, "Nicole", 2), new Employee(6, "Alice", 2), new Employee(7, "Bob", 3), new Employee(8, "Scarlett", 3));}private List<String> employeeNameFilter() { return Arrays.asList("Alice", "Mike", "Bob");}

Para o nosso exemplo, vamos filtrar a primeira lista de Funcionários com base na segunda lista com nomes de Funcionários para encontrar apenas os Funcionários com os nomes específicos.

Agora, vamos ver a abordagem tradicional-looping através de ambas as listas à procura de fósforos:

@Testpublic void givenEmployeeList_andNameFilterList_thenObtainFilteredEmployeeList_usingForEachLoop() { List<Employee> filteredList = new ArrayList<>(); List<Employee> originalList = buildEmployeeList(); List<String> nameFilter = employeeNameFilter(); for (Employee employee : originalList) { for (String name : nameFilter) { if (employee.getName().equals(name)) { filteredList.add(employee); // break; } } } assertThat(filteredList.size(), is(nameFilter.size()));}

esta é uma sintaxe simples, mas é bastante verbal, e na verdade bastante ineficiente. Simplificando, itera através do produto cartesiano dos dois conjuntos a fim de obter a nossa resposta.

mesmo adicionando uma pausa para sair cedo ainda vai iterar na mesma ordem que um produto cartesiano, no caso médio.

Se chamarmos o tamanho da lista de empregados n, então nameFilter estará na ordem tão grande, dando – nos uma classificação O(n2).

usando Streams e List#contém

vamos agora refazer o método anterior usando lambdas para simplificar a sintaxe e melhorar a legibilidade. Vamos também utilizar a Lista de#contém o método como o lambda de filtro:

@Testpublic void givenEmployeeList_andNameFilterList_thenObtainFilteredEmployeeList_usingLambda() { List<Employee> filteredList; List<Employee> originalList = buildEmployeeList(); List<String> nameFilter = employeeNameFilter(); filteredList = originalList.stream() .filter(employee -> nameFilter.contains(employee.getName())) .collect(Collectors.toList()); assertThat(filteredList.size(), is(nameFilter.size()));}

usando a Stream API, legibilidade foi muito melhorado, mas o nosso código permanece como ineficiente como o nosso método anterior, porque ainda iterar através do produto Cartesiano internamente. Assim, temos a mesma classificação O(n2).

usando fluxos com HashSet

para melhorar o desempenho, devemos usar a HashSet#contém método. Este método difere da Lista#contém, porque ele executa um código de hash de pesquisa, dando-nos uma constante de tempo de número de operações:

@Testpublic void givenEmployeeList_andNameFilterList_thenObtainFilteredEmployeeList_usingLambdaAndHashSet() { List<Employee> filteredList; List<Employee> originalList = buildEmployeeList(); Set<String> nameFilterSet = employeeNameFilter().stream().collect(Collectors.toSet()); filteredList = originalList.stream() .filter(employee -> nameFilterSet.contains(employee.getName())) .collect(Collectors.toList()); assertThat(filteredList.size(), is(nameFilterSet.size()));}

usando HashSet, o nosso código de eficiência melhorou muito apesar de não afetar a legibilidade. Uma vez que HashSet#contém runs em tempo constante, nós melhoramos nossa classificação para O(n).

conclusão

neste tutorial rápido, aprendemos a filtrar uma coleção por uma lista de valores e as desvantagens de usar o que pode parecer o método mais simples.

devemos sempre considerar a eficiência porque nosso código pode acabar funcionando em enormes conjuntos de dados, e problemas de desempenho podem ter consequências catastróficas em tais ambientes.todos os códigos apresentados neste artigo estão disponíveis no GitHub.

Começar com Mola 5 e Primavera de Inicialização 2, através do Aprender a Primavera curso:

>> confira O CURSO