Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return from lambda forEach() in java

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?

like image 651
samu Avatar asked May 01 '14 11:05

samu


People also ask

What does forEach return in Java?

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.

How do you return a value from a lambda function in Java?

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.

Can I use break in forEach Java?

break from loop is not supported by forEach. If you want to break out of forEach loop, you need to throw Exception.


2 Answers

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.

like image 137
Ian Roberts Avatar answered Sep 24 '22 14:09

Ian Roberts


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:

  • You want to add elements of an input structure to an output list if they match some predicate.

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:

  1. Turn your input structure into a stream (I am assuming here that it is of type Collection<Player>, now you have a Stream<Player>.
  2. Filter out all unwanted elements with a Predicate<Player>, mapping every player to the boolean true if it is wished to be kept.
  3. Collect the resulting elements in a list, via a Collector, here we can use one of the standard library collectors, which is Collectors.toList().

This also incorporates two other points:

  1. Code against interfaces, so code against List<E> over ArrayList<E>.
  2. Use diamond inference for the type parameter in 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.

like image 43
skiwi Avatar answered Sep 22 '22 14:09

skiwi