Java
Java 8
forEach
index
programming

Java 8 forEach with index

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Java 8 forEach does not provide an index parameter. That is not an omission you are supposed to patch over in every case. It is a sign that forEach is designed for element-oriented traversal, not indexed iteration. If your logic truly depends on the index, the best solution is often not "force an index into forEach". The best solution is to use a loop or an IntStream.

The Basic Limitation

This works:

java
List<String> items = Arrays.asList("apple", "banana", "orange");
items.forEach(System.out::println);

But there is no built-in (index, value) form. So if you need the index, you have to pick another pattern intentionally.

Best Option for Indexed Access: IntStream.range

For Java 8 code that wants stream style and an index, IntStream.range is usually the cleanest answer.

java
1import java.util.Arrays;
2import java.util.List;
3import java.util.stream.IntStream;
4
5List<String> items = Arrays.asList("apple", "banana", "orange");
6
7IntStream.range(0, items.size())
8         .forEach(i -> System.out.println(i + ": " + items.get(i)));

This is explicit about what is happening: you are iterating over indices, then reading each element by index.

If Indexing Is Central, a Classic Loop Is Still Fine

There is no prize for avoiding a normal for loop when it is the clearest tool.

java
1List<String> items = Arrays.asList("apple", "banana", "orange");
2
3for (int i = 0; i < items.size(); i++) {
4    System.out.println(i + ": " + items.get(i));
5}

If the real requirement is indexed access, this is often more readable than stream-based alternatives.

The AtomicInteger Trick Works, but It Is Usually a Smell

People often write:

java
1import java.util.concurrent.atomic.AtomicInteger;
2
3AtomicInteger index = new AtomicInteger();
4items.forEach(item -> {
5    System.out.println(index.getAndIncrement() + ": " + item);
6});

This works in sequential code, but it is usually not the best style. The atomic counter is not there because the problem is atomicity. It is there because forEach does not expose the index. That often makes the code feel more clever than necessary.

So a good rule is:

  • use IntStream.range if you want indexed stream style
  • use a normal loop if that is clearer
  • use AtomicInteger only when you have a very specific reason

Be Careful with Parallel Streams

Index-based logic and forEach become especially awkward with parallel streams. Once ordering and side effects matter, many of the normal stream advantages disappear.

java
items.parallelStream().forEach(System.out::println);

That is fine for independent side effects, but it is not a good environment for fake shared-index tricks. If you need ordered indexed behavior, stick with sequential structures.

Think About Why You Need the Index

Sometimes the need for an index is a hint that you actually want a different data shape. Examples:

  • pair two lists by position
  • generate numbered output
  • mutate by position

In those cases, iterating over indices directly is more honest than pretending you are doing element-only functional traversal.

Common Pitfalls

  • Expecting Java 8 forEach to provide an index like some other languages do.
  • Using AtomicInteger by default when a simple loop or IntStream.range would be clearer.
  • Mixing indexed logic with parallel streams and shared mutable state.
  • Choosing stream style for appearance even when indexed access is the real requirement.
  • Forgetting that items.get(i) is only appropriate when random access is efficient for the collection type.

Summary

  • Java 8 forEach does not natively expose an index.
  • 'IntStream.range(0, list.size()) is the cleanest indexed stream-style option.'
  • A classic for loop is often the clearest answer when index matters.
  • The AtomicInteger workaround is valid but usually not the best default.
  • If your logic depends on indices, write code that is honest about iterating over indices.

Course illustration
Course illustration

All Rights Reserved.