I am trying to change some for-each loops to lambda forEach()
-methods to discover the possibilities of lambda expressions. The following seems to be possible:
ArrayList<Player> playersOfTeam = new ArrayList<Player>(); for (Player player : players) { if (player.getTeam().equals(teamName)) { playersOfTeam.add(player); } }
With lambda forEach()
players.forEach(player->{if (player.getTeam().equals(teamName)) {playersOfTeam.add(player);}});
But the next one doesn't work:
for (Player player : players) { if (player.getName().contains(name)) { return player; } }
with lambda
players.forEach(player->{if (player.getName().contains(name)) {return player;}});
Is there something wrong in the syntax of the last line or is it impossible to return from forEach()
method?
Java 8 forEach() method takes consumer that will be running for all the values of Stream. Once forEach() method is invoked then it will be running the consumer logic for each and every value in the stream from a first value to last value. For each keeps the code very clean and in a declarative manner.
A return statement is not an expression in a lambda expression. We must enclose statements in braces ({}). However, we do not have to enclose a void method invocation in braces. The return type of a method in which lambda expression used in a return statement must be a functional interface.
break from loop is not supported by forEach. If you want to break out of forEach loop, you need to throw Exception.
The return
there is returning from the lambda expression rather than from the containing method. Instead of forEach
you need to filter
the stream:
players.stream().filter(player -> player.getName().contains(name)) .findFirst().orElse(null);
Here filter
restricts the stream to those items that match the predicate, and findFirst
then returns an Optional
with the first matching entry.
This looks less efficient than the for-loop approach, but in fact findFirst()
can short-circuit - it doesn't generate the entire filtered stream and then extract one element from it, rather it filters only as many elements as it needs to in order to find the first matching one. You could also use findAny()
instead of findFirst()
if you don't necessarily care about getting the first matching player from the (ordered) stream but simply any matching item. This allows for better efficiency when there's parallelism involved.
I suggest you to first try to understand Java 8 in the whole picture, most importantly in your case it will be streams, lambdas and method references.
You should never convert existing code to Java 8 code on a line-by-line basis, you should extract features and convert those.
What I identified in your first case is the following:
Let's see how we do that, we can do it with the following:
List<Player> playersOfTeam = players.stream() .filter(player -> player.getTeam().equals(teamName)) .collect(Collectors.toList());
What you do here is:
Collection<Player>
, now you have a Stream<Player>
.Predicate<Player>
, mapping every player to the boolean true if it is wished to be kept.Collector
, here we can use one of the standard library collectors, which is Collectors.toList()
.This also incorporates two other points:
List<E>
over ArrayList<E>
.new ArrayList<>()
, you are using Java 8 after all.Now onto your second point:
You again want to convert something of legacy Java to Java 8 without looking at the bigger picture. This part has already been answered by @IanRoberts, though I think that you need to do players.stream().filter(...)...
over what he suggested.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With