How to Iterate Over a Stream With Indices

Unlike the Collection elements, Stream elements cannot be accessed through indices, but there are still workarounds to get indices of the elements. In this Java tutorial, we will learn such few ways to iterate over Stream with indices.

1. Setup

For demo purposes, we are using the following Employee class.

public class Employee {

    private String name;
    private String email;
    private int age;
}

And we will also initialize an array of new employee objects which we will convert into a stream and then filter it according to indices:

Employee[] employees = {
    new Employee("Alexandru", "alexandru@gmail.com", 22),
    new Employee("Emanuela", "ema@gmail.com", 20),
    new Employee("George", "george@gmail.com", 32),
    new Employee("John", "john123@gmail.com", 25),
    new Employee("Liam", "liam123@gmail.com", 45),
    new Employee("Noah", "noah@outlook.com", 30),
    new Employee("Oliver", "oliver@yahoo.com", 47)
};

2. Using Custom Logic

For our first example, we will utilize the fact that our array elements can be accessed through indices. So, taking that in a sense, we will use the IntStream class to iterate over the numbers from 0 to the length of our array, filter them by the index, and map them with the corresponding Employee objects for the desired indices.

We can also collect the Employee instances in a new List if such a requirement exists.

IntStream.range(0, employees.length)
        .filter(i -> i % 2 == 0)
        .mapToObj(i -> employees[i])
        .forEach(System.out::println);

We can also use an AtomicInteger to hold the index of the stream elements. Then, we will get a stream from array using the stream() function and map each element of the stream with an index using the map() method, where the index is brought from the AtomicInteger by incrementing every time with the help of getAndIncrement() function.

AtomicInteger index = new AtomicInteger();

Arrays.stream(employees)
        .map(i -> index.getAndIncrement())
        .filter(i -> i % 2 == 0)
        .map(i -> employees[i])
        .forEach(System.out::println);

3. Using StreamUtils

For this example, we will use StreamUtils class from the protonpack library.

<dependency>
    <groupId>com.codepoetics</groupId>
    <artifactId>protonpack</artifactId>
    <version>1.16</version>
</dependency>

Now we can use the zipWithIndex() function from the StreamUtils class. This function will take the elements and zip each value with its index to create a stream of indexed values. After calling the function, we will filter the elements by their index, map them to their value and print each element.

StreamUtils.zipWithIndex(Arrays.stream(employees))
      .filter(e -> e.getIndex() % 2 == 0)
      .map(e -> e.getValue())
      .forEach(System.out::println);

3. Using StreamEx

Now we will use the EntryStream class from the StreamEx library.

<dependency>
    <groupId>one.util</groupId>
    <artifactId>streamex</artifactId>
    <version>0.8.1</version>
</dependency>

Now we can use the filterKeyValue() method to filter our values by their index. After that, we will take only the values and print them to the console.

EntryStream.of(employees)
    .filterKeyValue((index, name) -> index % 2 == 0)
    .values()
    .forEach(System.out::println);

4. Using Guava’s Streams

Guava is a group of core Java libraries from Google that contains new collection classes (such as multimap and multiset) and more! It is widely utilized on most Java projects within Google and by many other companies.

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>31.0.1-jre</version>
        </dependency>

We will use the mapWithIndex() function that returns a Stream that contains the results of applying the given function to the elements of the stream and their indexes in the stream. After applying the function, we will return null values for the odd indexes, and we will filter out them and print the result.

Streams.mapWithIndex(Arrays.stream(employees),
          (emp, index) -> index % 2 ==0 ? emp : null)
  .filter(emp -> emp != null)
  .forEach(System.out::println);	

5. Iteration using Vavre‘s Stream

Vavr is a functional library for Java. It allows the reduction of the amount of code and increases the robustness.

<dependency>
    <groupId>io.vavr</groupId>
    <artifactId>vavr</artifactId>
    <version>0.10.4</version>
</dependency>

Now we can use the zipWithIndex() function that will traverse our stream and return a tuple that contains the value and the index of the value. Now we can easily filter out the elements based on the parity of the index and print it on the console.

Stream.of(employees).zipWithIndex()
      .filter(tuple -> tuple._2 % 2 == 0)
      .map(tuple -> tuple._1)
      .forEach(System.out::println);

6. Conclusion

There are many ways to index our streams, and we should choose the solution that best suits our project and needs. Streams have gained a lot of awareness, and being able to also iterate through them with indices can be helpful. We can learn more about them from our articles about streams.

Happy Learning !!

Leave a Reply

0 Comments
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions, and frequently asked interview questions.