What you are looking for is called the map operation:

Thing[] functionedThings = Arrays.stream(things).map(thing -> functionWithReturn(thing)).toArray(Thing[]::new);

This method is used to map an object to another object; quoting the Javadoc, which says it better:

Returns a stream consisting of the results of applying the given function to the elements of this stream.

Note that the Stream is converted back to an array using the toArray(generator) method; the generator used is a function (it is actually a method reference here) returning a new Thing array.

Answer from Tunaki on Stack Overflow
🌐
Baeldung
baeldung.com › home › java › core java › guide to the java foreach loop
Guide to the Java forEach Loop | Baeldung
June 17, 2025 - Simply put, the Javadoc of forEach states that it “performs the given action for each element of the Iterable until all elements have been processed or the action throws an exception.” · And so, with forEach(), we can iterate over a collection and perform a given action on each element. For instance, let’s consider an enhanced for-loop version of iterating and printing a Collection of Strings: List names = List.of("Larry", "Steve", "James", "Conan", "Ellen"); for (String name : names) { LOG.info(name); }
Discussions

Return List from forEach using Stream in java - Stack Overflow
I am trying to convert below for-loop to forEach method with help Stream function using Java1.8, but I was messed up and also confused to do that. List valueList = new ArrayList ()... More on stackoverflow.com
🌐 stackoverflow.com
Return a value from Java 8 forEach loop - Stack Overflow
In the below example , someObjects is a set. I am trying to return true if a condition matches within the loop , however this doesn't seem to compile. However when I just add "return" it works fine... More on stackoverflow.com
🌐 stackoverflow.com
October 30, 2017
Why does the List interface have forEach, but not map?
why isn't every List a Stream? To answer this part of the question, it's because a stream is a fundamentally different datatype than a list. A list represents a collection of data, while a stream represents a pipeline for processing data. Streams can only be processed once, and are designed to perform multiple operations on some provided data. They don't store any intermediate results, and then do lazy processing once you specify a terminal operator (like toList() or forEach()). For example, if you had something like this: Stream a = List.of(1, 2, 3).stream(); Stream b = a.filter(n -> n > 1); Stream c = b.map(n -> String.valueOf(n)); List d = c.toList(); This is functionally identical to this: List d = List.of(1, 2, 3).stream() .filter(n -> n > 1) .map(n -> String.valueOf(n)) .toList(); If you inspected b, however, it would not contain any data about what elements were remaining, because the stream has not executed yet. Assigning the various steps of the stream along the way doesn't actually DO anything to the data, it just creates pointers to instances of the pipeline. As mentioned before, the pipeline can only be executed once, which means a stream is consumed when you perform a terminal operation on it. It also can't be executed if you chain it to another pipeline. If, in the example above, you tried to do b.toList(), you'd get an IllegalStateException, because b was already operated on. If you did c.toList(), you'd get a list of "2", "3". If you did c.toList() a second time, you'd once again get an IllegalStateExcecution, because c has already been consumed. The intermediate operators like map actually do nothing except modify the pipeline definition until you call toList at the end. Once you execute toList, then the pipeline operates in a lazy way, evaluating the data elements one at a time. So, to recap: List: collection of ordered data Stream: an operation pipeline definition More on reddit.com
🌐 r/java
90
121
October 26, 2024
How to get a list output from forEach loop in Java 8 Streams - Stack Overflow
I have two different lists of same objects but different properties and with a common identifier in those objects. I would like to iterate over the first list and get the corresponding object from ... More on stackoverflow.com
🌐 stackoverflow.com
May 31, 2018
Top answer
1 of 6
164

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.

2 of 6
20

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.

🌐
Codecademy
codecademy.com › docs › java › arraylist › .foreach()
Java | ArrayList | .forEach() | Codecademy
April 13, 2025 - The .forEach() method performs a specified action on each element of the ArrayList one by one. This method is part of the Java Collections Framework and was introduced in Java 8 as part of the Iterable interface, which ArrayList implements.
🌐
W3Schools
w3schools.com › java › ref_arraylist_foreach.asp
Java ArrayList forEach() Method
Java Examples Java Videos Java ... Java Certificate · ❮ ArrayList Methods · Use a lambda expression in the ArrayList's forEach() method to print every item in the list: import java.util.ArrayList; public class Main { ...
🌐
TutorialsPoint
tutorialspoint.com › break-or-return-from-java-8-stream-foreach
Break or return from Java 8 stream forEach?
Read More: Java Stream API Improvements. The forEach method is a terminal operation, which runs action on each element of the stream. It?s meant to process each element; it doesn?t allow early exit by break or return. List names = Arrays.asList("Alice", "Bob", "Charlie"); names.stream().forEach(name -> { System.out.println(name); });
🌐
W3Docs
w3docs.com › java
Break or return from Java 8 stream forEach?
However, since forEach() is a terminal operation and is not intended to be used as a loop, it is generally better to use a different method such as findFirst() or anyMatch() if you only need to find a single element in the stream. Here's an example of how you can use findFirst() to find the first even number in a stream and return from the operation: List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); Integer result = numbers.stream() .filter(n -> n % 2 == 0) .findFirst() .orElse(null); System.out.println(result); // prints 2
Find elsewhere
🌐
Medium
raphaeldelio.medium.com › why-wont-my-foreach-lambda-allow-me-to-exit-my-function-with-a-return-statement-986792e9c054
Why won't my forEach lambda allow me to exit my function with a return statement in Java? | by Raphael De Lio | Medium
January 25, 2024 - private boolean containtsOnlyFruits(List<Food> basket) { for (Food food : basket) { if (food.getFoodType() != FRUIT) { return false; } } return true; } Then, you remember you’ve been learning about Java Lambdas and a more functional approach, so you decide to write the same thing in a forEach lambda: private boolean containtsOnlyFruits(List<Food> basket) { basket.forEach(food -> { if (food.getFoodType() != FRUIT) { return false; } }); return true; } Just to come across an error: unexpected return value ·
🌐
Medium
neesri.medium.com › master-in-java-8-foreach-48ac3fc940dc
Master in the forEach() Method in Java 8 | by A cup of JAVA coffee with NeeSri | Medium
August 3, 2024 - action is an instance of the BiConsumer functional interface, which represents an operation that accepts two input arguments (key and value) and returns no result. Map<String, Integer> map = new HashMap<>(); map.put("apple", 1); map.put("banana", 2); map.put("orange", 3); // Java 8 forEach map.forEach((key, value) -> System.out.println(key + " -> " + value)); // Java 7 loop for (Map.Entry<String, Integer> entry : map.entrySet()) { System.out.println(entry.getKey() + " -> " + entry.getValue()); } List<String> list = Arrays.asList("apple", "banana", "orange"); // Java 8 forEach list.forEach(item -> System.out.println(item)); // Java 7 loop for (String item : list) { System.out.println(item); }
🌐
Tabnine
tabnine.com › home page › code › java › java.util.list
java.util.List.forEach java code examples | Tabnine
public static List<byte[]> getUtf8ByteArrays(List<String> strings) { if (CollectionUtils.isEmpty(strings)) { return Collections.emptyList(); } List<byte[]> byteArrays = new ArrayList<>(strings.size()); strings.forEach(s -> byteArrays.add(Bytes.toBytes(s))); return byteArrays; }
🌐
HowToDoInJava
howtodoinjava.com › home › java 8 › java foreach()
Java forEach() with Examples - HowToDoInJava
February 6, 2023 - List<String> list = Arrays.asList("Alex", "Brian", "Charles"); list.forEach(System.out::println); Since Java 8, the forEach() has been added in the following classes or interfaces:
🌐
Stack Abuse
stackabuse.com › guide-to-java-streams-foreach-with-examples
Guide to Java Streams: forEach() with Examples
July 27, 2020 - The forEach() method is a really useful method to use to iterate over collections in Java in a functional approach. In certain cases, they can massively simplify the code and enhance clarity and brevity. In this article, we've gone over the basics of using a forEach() and then covered examples of the method on a List, Map and Set. We've covered the difference between the for-each loop and the forEach(), as well as the difference between basing logic on return values versus side-effects.
🌐
Java67
java67.com › 2016 › 01 › how-to-use-foreach-method-in-java-8-examples.html
10 Examples of forEach() method in Java 8 | Java67
We have already seen a glimpse of the powerful feature of Stream API in my earlier post, how to use Stream API in Java 8, here we will see it again but in the context of the forEach() method. let's now only print elements that start with "a", following code will do that for you, startWith() is a method of String class, which return true if String is starting with String "a" or it will return false. Once the list is filtered then forEach() method will print all elements starting with String "a", as shown below:
🌐
ZetCode
zetcode.com › java › foreach
Java forEach - forEach on Java lists, maps, sets
In this article, we demonstrate how to effectively utilize the Java forEach method. We explore its application with consumers and provide practical examples of using forEach to iterate over lists, maps, and set collections, showcasing its versatility in handling various data structures.
🌐
Mkyong
mkyong.com › home › java8 › java 8 foreach examples
Java 8 forEach examples - Mkyong.com
December 4, 2020 - We can now reuse the same Consumer method and pass it to the forEach method of List and Stream. ... package com.mkyong.java8.misc; import java.util.*; import java.util.function.Consumer; import java.util.stream.Stream; public class ForEachConsumer { public static void main(String[] args) { List<String> list = Arrays.asList("abc", "java", "python"); Stream<String> stream = Stream.of("abc", "java", "python"); // convert a String to a Hex Consumer<String> printTextInHexConsumer = (String x) -> { StringBuilder sb = new StringBuilder(); for (char c : x.toCharArray()) { String hex = Integer.toHexString(c); sb.append(hex); } System.out.print(String.format("%n%-10s:%s", x, sb.toString())); }; // pass a Consumer list.forEach(printTextInHexConsumer); stream.forEach(printTextInHexConsumer); } }
🌐
Reddit
reddit.com › r/java › why does the list interface have foreach, but not map?
r/java on Reddit: Why does the List interface have forEach, but not map?
October 26, 2024 -

Pretty much the title: It's kind of annoying and "bloaty" to create a Stream from the List, just to do a map (or filter) and then convert it back to List. Isn't it also inefficient?

Is there a solid, philosophical justification behind this choice, or it is like that mostly for backward compatibility?

And on a broader, more non-orthodox note, why isn't every List a Stream? I fully understand the other way round, i.e. obviously not every Stream is a List, but this way..

Thanks a lot

Top answer
1 of 19
163
why isn't every List a Stream? To answer this part of the question, it's because a stream is a fundamentally different datatype than a list. A list represents a collection of data, while a stream represents a pipeline for processing data. Streams can only be processed once, and are designed to perform multiple operations on some provided data. They don't store any intermediate results, and then do lazy processing once you specify a terminal operator (like toList() or forEach()). For example, if you had something like this: Stream a = List.of(1, 2, 3).stream(); Stream b = a.filter(n -> n > 1); Stream c = b.map(n -> String.valueOf(n)); List d = c.toList(); This is functionally identical to this: List d = List.of(1, 2, 3).stream() .filter(n -> n > 1) .map(n -> String.valueOf(n)) .toList(); If you inspected b, however, it would not contain any data about what elements were remaining, because the stream has not executed yet. Assigning the various steps of the stream along the way doesn't actually DO anything to the data, it just creates pointers to instances of the pipeline. As mentioned before, the pipeline can only be executed once, which means a stream is consumed when you perform a terminal operation on it. It also can't be executed if you chain it to another pipeline. If, in the example above, you tried to do b.toList(), you'd get an IllegalStateException, because b was already operated on. If you did c.toList(), you'd get a list of "2", "3". If you did c.toList() a second time, you'd once again get an IllegalStateExcecution, because c has already been consumed. The intermediate operators like map actually do nothing except modify the pipeline definition until you call toList at the end. Once you execute toList, then the pipeline operates in a lazy way, evaluating the data elements one at a time. So, to recap: List: collection of ordered data Stream: an operation pipeline definition
2 of 19
24
Because forEach is easy to fully specify, as it just returns void. map would need to return some List, but what implementation? Stream allows you to specify, but if List would, things would get complicated. And if List, why not Set, Collection, or Iterable (forEach is actually in Iterable)? And if it's in Iterable, the question of the implementation of the returned type becomes even more complex. But why just map? Follow this through, and repeat for filter and flatMap, and Iterable becomes Stream, only more complicated, because an Iterable can be consumed multile times.
🌐
Baeldung
baeldung.com › home › java › java collections › the difference between collection.stream().foreach() and collection.foreach()
The Difference Between stream().forEach() and forEach() | Baeldung
September 17, 2025 - Java only requires all threads to finish before any terminal operation, such as Collectors.toList(), is called. Let’s look at an example where we first call forEach() directly on the collection, and second, on a parallel stream: list.forEach(System.out::print); System.out.print(" "); list.parallelStream().forEach(System.out::print);
Top answer
1 of 3
12

Instead of using a forEach just use streams from the beginning:

List<PersonWrapper> wrapperList = jrList.stream()
    .flatMap(jr -> seniorList.stream()
         .filter(sr -> jr.getName().equals(sr.getName()))
         .map(sr -> new PersonWrapper(jr, sr))
    )
    .collect(Collectors.toList());

By using flatMap you can flatten a stream of streams (Stream<Stream<PersonWrapper>>) into a single stream (Stream<PersonWrapper>)

If you can't instantiate wrapperList by yourself or really need to append to it. You can alter above snippet to following:

List<PersonWrapper> wrapperList = new ArrayList<>();

jrList.stream()
    .flatMap(jr -> seniorList.stream()
         .filter(sr -> jr.getName().equals(sr.getName()))
         .map(sr -> new PersonWrapper(jr, sr))
    )
    .forEach(wrapperList::add);
2 of 3
4

While Lino's answer is certainly correct. I would argue that if a given person object in jrList can only ever have one corresponding match in seniorList maximum, in other words, if it's a 1-1 relationship then you can improve upon the solution given by Lino by finding the first match as follows:

List<PersonWrapper> resultSet = jrList.stream()
                .map(p -> seniorList.stream()
                        .filter(sr -> p.getName().equals(sr.getName()))
                        .findFirst()
                        .map(q -> new PersonWrapper(p, q))
                        .get())
                .collect(Collectors.toList());

or if there is no guarantee that each person in jrList will have a corresponding match in seniorList then change the above query to:

List<PersonWrapper> resultSet = jrList.stream()
                .map(p -> seniorList.stream()
                        .filter(sr -> p.getName().equals(sr.getName()))
                        .findFirst()
                        .map(q -> new PersonWrapper(p, q))
                        .orElse(null))
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

The difference is that now instead of calling get() on the result of findFirst() we provide a default with orElse in case findFirst cannot find the corresponding value and then we filter the null values out in the subsequent intermediate operation as they are not needed.