Depends on where you want to increment.

Either

userList.stream()
        .map(user -> {
               counter.getAndIncrement();
               return new Foo(getName(user), getId(user));
            })
        .forEach(fooList::add);

or

userList.stream()
        .map(user -> new Foo(getName(user), getId(user)))
        .forEach(foo -> {
            fooList.add(foo);
            counter.getAndIncrement();
        });
Answer from bradimus on Stack Overflow
🌐
Baeldung
baeldung.com › home › java › java collections › how to access an iteration counter in a for each loop
How to Access an Iteration Counter in a For Each Loop | Baeldung
January 8, 2024 - Let’s see this in use by our ... })); Inside the forEach is a call to the withCounter function to create an object which both tracks the count and acts as the Consumer that the forEach operation passes its values too...
🌐
Baeldung
baeldung.com › home › java › java streams › how to iterate over a stream with indices
How to Iterate Over a Stream With Indices | Baeldung
February 28, 2025 - In a parallel stream, elements may be processed concurrently by multiple threads, and this can result in an unpredictable order of element processing. The getAndIncrement() is atomic, the order of element processing isn’t guaranteed. This can cause inconsistent index assignments, as threads may increment the counter out of sync with the actual order of elements:
🌐
Java by examples
javaquery.com › 2015 › 07 › how-to-iterate-over-stream-and.html
Java by examples: How to iterate over stream and increment index value in Lambda Expression?
*/ List<String> listNames = new ArrayList<String>(Arrays.asList("Vicky Thakor", "Chirag Thakor", "Dave Hill", "Finn Jones", "Heer Thakor")); listNames.stream() .filter(name -> name.endsWith("Thakor")) .forEach(name -> { /* Get the previous value of count and increment it by `1` */ atomicInteger.getAndIncrement(); /* Print the name */ System.out.println(name); }); /* Get value of `atomicInteger` */ System.out.println("Total match found using `stream()`: " + atomicInteger.get()); System.out.println("+++++++++++++++++++++++++++"); } /** * Example of using AtomicInteger in `parallelStream()` */ public void UsingParallelStream() { /* Create object of AtomicInteger with initial value `0` */ AtomicInteger atomicInteger = new AtomicInteger(0); /* Create list of names.
🌐
Medium
nicksamoylov.medium.com › java-streams-19-count-foreach-or-foreachordered-2d78ff5e6101
Java streams 19. Count, forEach, or forEachOrdered | by Nick Samoylov | Medium
May 10, 2020 - Java streams 19. Count, forEach, or forEachOrdered With this post, we start discussing terminal operations–the last from the three Stream methods categories: factory methods, intermediate …
Top answer
1 of 3
4

Iterating over a List is not expensive per se. The expenses of repeated Stream operations depend on the actual repeated intermediate operations. Due to the optimizing environment, the code is executed in, two single-purpose loops may turn out to be more efficient than putting two concerns into one loop.

Note that the count does not depend on the result of the map operation, hence, you can omit it for the count operation:

List<String> names = ...;
names.stream().filter(...).map(...).forEach(...);
// Then count them:
long count = names.stream().filter(...).count();

This is the variant to try and measure, for comparison with Stream approaches doing both actions at once.

Note that forEach does not guaranty your action to be performed in order and in case of a parallel stream, it could even get evaluated concurrently. Similar behavior would apply to peek, as well as any attempt to insert the actual action into a map function.

An attempt to use something like

long count = names.stream().filter(...).map(...)
    .map(x -> {                                   // don't do this
        // your action
        return x;
    }).count();

bears the additional problem that an implementation might consider the same thing as said above, the map function’s result is irrelevant to the count, so it could get skipped, even if the current implementation does not.

Likewise, using

long count = names.stream().filter(...).map(...)
    .peek(x -> {                                  // don't do this
        // your action
    }).count();

bears some risk. The last map step is irrelevant to the final count, so it could get skipped, in which case the peek action must get skipped too, as the input for it doesn’t exist. There is no guaranty that obsolete intermediate operations are kept only for the sake of peek operations. We can only speculate, how radical the implementers will exploit this aspect. But the only practical example in the current reference implementation, is the skipping of the entire pipeline when the count is predictable beforehand, which also skips all peek operations. This suggests that we should never rely on the execution of peek actions.

But when you use

int count = names.stream().filter(...).map(...)
    .mapToInt(x -> {                   // don't assume sequential in-order execution
        // your action
        return 1;
    }).sum();

the end result is dependent on the function containing the action, so it will always be evaluated. But unlike forEach, which can be replaced by forEachOrdered, to get guaranteed non-concurrent, ordered execution, there is no such option for the mapping function.

2 of 3
2

This is not particularly more elegant or efficient, but it's an alternative you didn't list (a mutable reduction):

AtomicInteger count = names.stream().collect(
        AtomicInteger::new,
        (sum, name) -> {
            //forEach action here
            sum.incrementAndGet();
        }, 
        (n1, n2) -> {
            n1.addAndGet(n2.get());
        });
🌐
Medium
medium.com › @satyendra.jaiswal › unveiling-the-power-of-terminal-operations-in-java-stream-api-foreach-count-collect-min-max-b592fe55eb24
Unveiling the Power of Terminal Operations in Java Stream API: forEach, count, collect, min, max, and reduce | by Satyendra Jaiswal | Medium
January 19, 2025 - The Java Stream API has revolutionized the way we manipulate data, bringing functional programming paradigms to the forefront. Among its key features, terminal operations stand out, providing the means to materialize the transformations defined by intermediate operations. In this exploration, we delve into the intricacies of five powerful terminal operations: forEach, count, collect, min, max, and reduce.
Find elsewhere
🌐
Oracle
docs.oracle.com › javase › 8 › docs › api › java › util › stream › Stream.html
Stream (Java Platform SE 8 )
1 week ago - A stream pipeline consists of a source (which might be an array, a collection, a generator function, an I/O channel, etc), zero or more intermediate operations (which transform a stream into another stream, such as filter(Predicate)), and a terminal operation (which produces a result or side-effect, such as count() or forEach(Consumer)).
🌐
HowToDoInJava
howtodoinjava.com › home › java 8 › java stream count() matches with filter()
Java Stream count() Matches with filter()
March 4, 2022 - In the given example, we are counting all the even numbers in the stream. long count = LongStream.of(1,2,3,4,5,6,7,8,9) .filter(i -> i%2 == 0) .count(); //or //.collect(Collectors.counting()) Happy Learning !! Sourcecode on Github · Subscribe · 0 Comments · Most Voted · Newest Oldest · Inline Feedbacks · View all comments · Load More Comments · Java 8 Features · Java 8 forEach ·
🌐
Stack Abuse
stackabuse.com › guide-to-java-streams-foreach-with-examples
Guide to Java Streams: forEach() with Examples
July 27, 2020 - AtomicInteger result2 = new AtomicInteger(); targetList.stream().forEach(integer -> { if (integer > 0) result2.addAndGet(1); }); System.out.println("Result: " + result2); The forEach() method is a really useful method to use to iterate over collections in Java in a functional approach.
🌐
Mkyong
mkyong.com › home › java8 › java 8 foreach examples
Java 8 forEach examples - Mkyong.com
December 4, 2020 - In Java 8, we can use the new forEach to loop or iterate a Map, List, Set, or Stream.
🌐
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 - The forEach() method introduced in Java 8 allows for concise iteration over collections, enhancing code readability and maintainability. It operates on streams and accepts a lambda expression or method reference to perform an action on each element.
🌐
javaspring
javaspring.net › blog › incrementing-counter-in-stream-foreach-java-8
How to Increment an AtomicInteger Counter in Java 8 Stream forEach Loop — javaspring.net
AtomicInteger is the go-to choice for safely incrementing counters in Java 8 Stream forEach loops, especially in parallel streams. It avoids the pitfalls of regular integers and ensures thread safety with minimal overhead.
🌐
GeeksforGeeks
geeksforgeeks.org › java › foreach-loop-vs-stream-foreach-vs-parallel-stream-foreach
foreach() loop vs Stream foreach() vs Parallel Stream foreach() - GeeksforGeeks
July 12, 2025 - For example, if we want to print only the first 2 values of any collection or array and then we want to return any value, it can be done in foreach loop in Java. The code below is for printing the 2nd element of an array. ... public class GFG { public static String frechlop(String[] geek) { int count = 0; for (String var : geek) { if (count == 1) return var; count++; } return ""; } public static void main(String[] args) throws Exception { String[] arr1 = { "Geeks", "For", "Geeks" }; String secelt = frechlop(arr1); System.out.println(secelt); } } ... Lambda operator is used: In stream().forEach(), lambdas are used and thus operations on variables outside the loop are not allowed.
🌐
TutorialsPoint
tutorialspoint.com › break-or-return-from-java-8-stream-foreach
Break or return from Java 8 stream forEach?
If you?re using Java 9 or above you can use the takeWhile method to process elements until some condition is met. names.stream() .takeWhile(name -> !name.equals("Bob")) .forEach(System.out::println);
🌐
GeeksforGeeks
geeksforgeeks.org › java › stream-count-method-java
Stream count() method in Java with examples - GeeksforGeeks
December 26, 2025 - Stream.count() method returns the number of elements in a stream. It is a terminal operation and a special case of reduction, which combines a sequence of elements into a single summary result.
🌐
jOOQ
blog.jooq.org › 3-reasons-why-you-shouldnt-replace-your-for-loops-by-stream-foreach
3 Reasons why You Shouldn’t Replace Your for-loops by Stream.forEach() – Java, SQL and jOOQ.
April 2, 2020 - Performance is killed when you chose java, so just put the work to adapt to the new world, even if you’re already old. ... The author is just saying to use you common sense before running and changing all “for” loops to streams. By the way not necessarily new == better, old == worse… Once you get older and wiser you will realize that ... While list.forEach() produces very little overhead, chances are that you will soon add the stream() call nonetheless, because you’re going to get bored of putting an if statement in that lambda (replacing it by filter) or some local variable assignments (replacing them by map), or a nested forEach() call (replacing them by flatMap()).
🌐
Java Code Geeks
javacodegeeks.com › home › core java
For Loops vs. Stream.forEach: When to Use Which - Java Code Geeks
August 11, 2024 - Instead of focusing on how to perform ... to perform. The Stream.forEach method is a terminal operation within the Stream API, used to apply a given action to each element of the stream....