Estou tentando alterar alguns loops for-each para forEach()
métodos lambda para descobrir as possibilidades das expressões lambda. O seguinte parece ser possível:
ArrayList<Player> playersOfTeam = new ArrayList<Player>();
for (Player player : players) {
if (player.getTeam().equals(teamName)) {
playersOfTeam.add(player);
}
}
Com lambda forEach()
players.forEach(player->{if (player.getTeam().equals(teamName)) {playersOfTeam.add(player);}});
Mas o próximo não funciona:
for (Player player : players) {
if (player.getName().contains(name)) {
return player;
}
}
com lambda
players.forEach(player->{if (player.getName().contains(name)) {return player;}});
Há algo errado na sintaxe da última linha ou é impossível retornar do forEach()
método?
return
dentro de uma instrução lambda retorna do próprio lambda, não de qualquer coisa chamada lambda. Eles encerram um fluxo antecipadamente ("curto-circuito"),findFirst
conforme mostrado na resposta de Ian Roberts .Respostas:
O
return
there está retornando da expressão lambda em vez do método que o contém. Em vez deforEach
você precisa parafilter
o fluxo:Aqui,
filter
restringe o fluxo aos itens que correspondem ao predicado e, emfindFirst
seguida, retorna umOptional
com a primeira entrada correspondente.Isso parece menos eficiente do que a abordagem for-loop, mas na verdade
findFirst()
pode causar curto-circuito - não gera todo o fluxo filtrado e, em seguida, extrai um elemento dele, em vez disso, filtra apenas quantos elementos precisa para encontre o primeiro correspondente. Você também pode usar emfindAny()
vez defindFirst()
se não se preocupar necessariamente em obter o primeiro jogador correspondente do fluxo (ordenado), mas simplesmente qualquer item correspondente. Isso permite melhor eficiência quando há paralelismo envolvido.fonte
orElse(null)
em umOptional
. O ponto principal deOptional
é fornecer uma maneira de indicar a presença ou ausência de um valor em vez de sobrecarregar o nulo (o que leva a NPEs). Se você usá-optional.orElse(null)
lo, ele recupera todos os problemas com nulos. Eu o usaria apenas se você não pudesse modificar o chamador e ele realmente estivesse esperando um nulo.Optional<Player>
seria uma maneira mais natural de se ajustar ao paradigma de streams. Eu estava apenas tentando mostrar como duplicar o comportamento existente usando lambdas.Eu sugiro que você primeiro tente entender o Java 8 como um todo, o mais importante no seu caso serão streams, lambdas e referências de método.
Você nunca deve converter o código existente em código Java 8 linha por linha, você deve extrair recursos e convertê-los.
O que identifiquei em seu primeiro caso é o seguinte:
Vamos ver como fazemos isso, podemos fazer com o seguinte:
O que você faz aqui é:
Collection<Player>
, agora você tem umStream<Player>
.Predicate<Player>
, mapeando cada jogador para o verdadeiro booleano, se desejar mantê-lo.Collector
, aqui podemos usar um dos coletores de biblioteca padrão, que éCollectors.toList()
.Isso também incorpora dois outros pontos:
List<E>
overArrayList<E>
.new ArrayList<>()
, você está usando Java 8 afinal.Agora em seu segundo ponto:
Você deseja novamente converter algo de legado Java em Java 8 sem olhar o quadro geral. Esta parte já foi respondida por @IanRoberts , embora eu ache que você precisa refazer
players.stream().filter(...)...
o que ele sugeriu.fonte
Se quiser retornar um valor booleano, você pode usar algo assim (muito mais rápido do que filtrar):
fonte
Isso é o que me ajudou:
Retirado do Java 8 Finding Specific Element in List with Lambda
fonte
Você também pode lançar uma exceção:
Nota:
Por uma questão de legibilidade, cada etapa do fluxo deve ser listada em uma nova linha.
se sua lógica é vagamente "orientada por exceções", como se houver um lugar em seu código que captura todas as exceções e decide o que fazer a seguir. Use o desenvolvimento orientado por exceções apenas quando puder evitar sobrecarregar sua base de código com múltiplos
try-catch
e lançar essas exceções são para casos muito especiais que você espera e podem ser tratados de forma adequada.)fonte