Encontrar elemento
Agora estamos familiarizados com esse método elegantemente projetado de transformar coleções, mas é inútil para encontrar elementos. Mas o método do filtro nasceu para isso.
Agora queremos remover os nomes que começam com N de uma lista de nomes. É claro que pode não haver nenhum e o resultado pode ser um conjunto vazio. Vamos implementá-lo primeiro usando o método antigo.
Copie o código do código da seguinte forma:
final List<String>startWithN = new ArrayList<String>();
for(String nome: amigos) {
if(nome.startsWith("N")) {
começaComN.add(nome);
}
}
Escrever tanto código para um evento tão simples é bastante detalhado. Primeiro criamos uma variável e depois a inicializamos em uma coleção vazia. Em seguida, percorra a coleção original e encontre os nomes que começam com a letra especificada. Se encontrado, ele será inserido na coleção.
Vamos usar o método de filtro para reconstruir o código acima e ver quão poderoso ele é.
Copie o código do código da seguinte forma:
lista final<String> iniciaComN =
amigos.stream()
.filter(nome -> nome.startsWith("N"))
.collect(Collectors.toList());
O método filter recebe uma expressão lambda que retorna um valor booleano. Se a expressão for avaliada como verdadeira, esse elemento no contexto de execução será adicionado ao conjunto de resultados; caso contrário, ele será ignorado. O que finalmente é retornado é um Steam, que contém apenas os elementos cuja expressão retorna verdadeira. Finalmente, usamos um método collect para converter a coleção em uma lista - discutiremos esse método com mais profundidade em Usando o método collect e a classe Collecters na página 52.
Vamos imprimir os elementos deste conjunto de resultados:
Copie o código do código da seguinte forma:
System.out.println(String.format("Encontrados %d nomes",startWithN.size()));
É óbvio pela saída que este método encontrou todos os elementos correspondentes na coleção.
Copie o código do código da seguinte forma:
Foram encontrados 2 nomes
O método filter, assim como o método map, também retorna um iterador, mas isso é tudo. A coleção retornada por map tem o mesmo tamanho da coleção de entrada, mas é difícil dizer qual filtro retorna. O intervalo de tamanho do conjunto retornado, de 0 ao número de elementos no conjunto de entrada. Ao contrário do mapa, o filtro retorna um subconjunto do conjunto de entrada.
Até agora, estamos muito satisfeitos com a simplicidade do código trazida pelas expressões lambda, mas se não tomarmos cuidado, o problema de redundância de código começará a crescer lentamente. Vamos discutir esse assunto abaixo.
Reutilização de expressões lambda
As expressões lambda parecem muito concisas, mas na verdade é fácil tornar o código redundante se você não tomar cuidado. A redundância levará à baixa qualidade do código e à dificuldade de manutenção. Se quisermos fazer uma alteração, teremos que alterar vários códigos relacionados juntos;
Evitar a redundância também pode nos ajudar a melhorar o desempenho. O código relevante está concentrado em um só lugar, para que possamos analisar seu desempenho e depois otimizar o código aqui, o que pode facilmente melhorar o desempenho do código.
Agora vamos ver por que o uso de expressões lambda pode facilmente levar à redundância de código e considerar como evitá-la.
Copie o código do código da seguinte forma:
lista final<String> amigos =
Arrays.asList("Brian", "Nate", "Neal", "Raju", "Sara", "Scott");
final List<String> editores =
Arrays.asList("Brian", "Jackie", "John", "Mike");
final List<String> camaradas =
Arrays.asList("Kate", "Ken", "Nick", "Paula", "Zach");
Queremos filtrar nomes que começam com uma determinada letra.
Queremos filtrar nomes que começam com uma determinada letra. Vamos simplesmente implementá-lo usando primeiro o método de filtro.
Copie o código do código da seguinte forma:
contagem longa finalFriendsStartN =
amigos.stream()
.filter(nome -> nome.startsWith("N")).count();
contagem longa finalEditorsStartN =
editores.stream()
.filter(nome -> nome.startsWith("N")).count();
contagem longa finalComradesStartN =
camaradas.stream()
.filter(nome -> nome.startsWith("N")).count();
As expressões lambda fazem o código parecer conciso, mas, sem saber, trazem redundância ao código. No exemplo acima, se quisermos alterar a expressão lambda, teremos que alterar mais de um local – o que não é possível. Felizmente, podemos atribuir expressões lambda a variáveis e reutilizá-las como objetos.
O método filter, o receptor da expressão lambda, recebe uma referência à interface funcional java.util.function.Predicate. Aqui, o compilador Java é útil novamente. Ele gera uma implementação do método de teste do Predicate usando a expressão lambda especificada. Agora podemos pedir mais explicitamente ao compilador Java para gerar este método em vez de gerá-lo onde os parâmetros são definidos. No exemplo acima, podemos armazenar explicitamente a expressão lambda em uma referência do tipo Predicate e, em seguida, passar essa referência para o método de filtro; isso pode facilmente evitar a redundância de código.
Vamos refatorar o código anterior para torná-lo compatível com o princípio DRY. (Princípio Don't Repeat Yoursef - DRY -, consulte o livro The Pragmatic Programmer: From Journeyman to Master [HT00]).
Copie o código do código da seguinte forma:
final Predicate<String>startWithN = nome -> name.startsWith("N");
contagem longa finalFriendsStartN =
amigos.stream()
.filter(iniciaComN)
.contar();
contagem longa finalEditorsStartN =
editores.stream()
.filter(iniciaComN)
.contar();
contagem longa finalComradesStartN =
camaradas.stream()
.filter(iniciaComN)
.contar();
Agora, em vez de escrever a expressão lambda novamente, nós a escrevemos uma vez e a armazenamos em uma referência do tipo Predicate chamadastartsWithN. Nas três chamadas de filtro seguintes, o compilador Java viu a expressão lambda disfarçada de Predicado, sorriu e aceitou-a silenciosamente.
Esta variável recém-introduzida elimina a redundância de código para nós. Mas infelizmente, como veremos mais tarde, o inimigo voltará em breve para se vingar. Vamos ver que armas mais poderosas podem destruí-los para nós.