How to Iterate Over a Stream With Indices

1. Overview

Java 8 Streams are not collections and elements cannot be accessed using their indices, but there are still a few tricks to make this possible.

In this short article, we’re going to look at how to iterate over a Stream using IntStream, StreamUtils, EntryStream, and Vavr‘s Stream.

2. Using Plain Java

We can navigate through a Stream using an Integer range, and also benefit from the fact that the original elements are in an array or a collection accessible by indices.

Let’s implement a method which iterates with indices and demonstrates this approach.

Simply put, we want to get an array of Strings and only select even indexed elements:

public List<String> getEvenIndexedStrings(String[] names) {
    List<String> evenIndexedNames = IntStream
      .range(0, names.length)
      .filter(i -> i % 2 == 0)
      .mapToObj(i -> names[i])
      .collect(Collectors.toList());
    
    return evenIndexedNames;
}

Let’s now test out the implementation:

@Test
public void whenCalled_thenReturnListOfEvenIndexedStrings() {
    String[] names 
      = {"Afrim", "Bashkim", "Besim", "Lulzim", "Durim", "Shpetim"};
    List<String> expectedResult 
      = Arrays.asList("Afrim", "Besim", "Durim");
    List<String> actualResult 
      = StreamIndices.getEvenIndexedStrings(names);
   
    assertEquals(expectedResult, actualResult);
}

3. Using StreamUtils

Another way to iterate with indices can be done using zipWithIndex() method of StreamUtils from the proton-pack library (the latest version can be found here).

First, you need to add it to your pom.xml:

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

Now, let’s look at the code:

public List<Indexed<String>> getEvenIndexedStrings(List<String> names) {
    List<Indexed<String>> list = StreamUtils
      .zipWithIndex(names.stream())
      .filter(i -> i.getIndex() % 2 == 0)
      .collect(Collectors.toList());
    
    return list;
}

The following tests this method and passes successfully:

@Test
public void whenCalled_thenReturnListOfEvenIndexedStrings() {
    List<String> names = Arrays.asList(
      "Afrim", "Bashkim", "Besim", "Lulzim", "Durim", "Shpetim");
    List<Indexed<String>> expectedResult = Arrays.asList(
      Indexed.index(0, "Afrim"), 
      Indexed.index(2, "Besim"), 
      Indexed.index(4, "Durim"));
    List<Indexed<String>> actualResult 
      = StreamIndices.getEvenIndexedStrings(names);
    
    assertEquals(expectedResult, actualResult);
}

4. Using StreamEx

We can also iterate with indexes using filterKeyValue() of EntryStream class from StreamEx library (the latest version can be found here). First, we need to add it to our pom.xml:

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

Let’s see a simple application of this method using our previous example:

public List<String> getEvenIndexedStringsVersionTwo(List<String> names) {
    return EntryStream.of(names)
      .filterKeyValue((index, name) -> index % 2 == 0)
      .values()
      .toList();
}

We’ll use a similar test to test this:

@Test
public void whenCalled_thenReturnListOfEvenIndexedStringsVersionTwo() {
    String[] names 
      = {"Afrim", "Bashkim", "Besim", "Lulzim", "Durim", "Shpetim"};
    List<String> expectedResult 
      = Arrays.asList("Afrim", "Besim", "Durim");
    List<String> actualResult 
      = StreamIndices.getEvenIndexedStrings(names);
   
   assertEquals(expectedResult, actualResult);
}

5. Iteration Using Vavre‘s Stream

Another plausible way of iteration is using zipWithIndex() method of Vavr (previously known as Javaslang)’s Stream implementation:

public List<String> getOddIndexedStringsVersionTwo(String[] names) {
    return Stream
      .of(names)
      .zipWithIndex()
      .filter(tuple -> tuple._2 % 2 == 1)
      .map(tuple -> tuple._1)
      .toJavaList();
}

We can test this example with the following method:

@Test
public void whenCalled_thenReturnListOfOddStringsVersionTwo() {
    String[] names 
      = {"Afrim", "Bashkim", "Besim", "Lulzim", "Durim", "Shpetim"};
    List<String> expectedResult 
      = Arrays.asList("Bashkim", "Lulzim", "Shpetim");
    List<String> actualResult 
      = StreamIndices.getOddIndexedStringsVersionTwo(names);

    assertEquals(expectedResult, actualResult);
}

If you want to read more about Vavr, check this article.

6. Conclusion

In this quick tutorial, we saw four approaches on how to iterate through streams using indices. Streams have gotten a lot of attention and being able to also iterate through them with indices can be helpful.

There are a lot of features that are included in Java 8 Streams, some of which are already covered on VietMX’s Blog.

The code for all the examples explained here, and much more can be found over on GitHub.

Related posts:

Java Program to Generate N Number of Passwords of Length M Each
Arrays.asList vs new ArrayList(Arrays.asList())
Java Program to Compute Cross Product of Two Vectors
LinkedHashSet trong java
Java Program to Find Number of Spanning Trees in a Complete Bipartite Graph
Guide to Character Encoding
Setting a Request Timeout for a Spring REST API
Java Program to Implement wheel Sieve to Generate Prime Numbers Between Given Range
Spring NoSuchBeanDefinitionException
Java Program to Perform Arithmetic Operations on Numbers of Size
Refactoring Design Pattern với tính năng mới trong Java 8
Spring Boot Configuration with Jasypt
Spring Boot - Enabling Swagger2
Guide to Mustache with Spring Boot
Introduction to Project Reactor Bus
HashMap trong Java hoạt động như thế nào?
Java Program to Print only Odd Numbered Levels of a Tree
Spring Cloud – Bootstrapping
Java Program to Find Location of a Point Placed in Three Dimensions Using K-D Trees
Spring Data MongoDB – Indexes, Annotations and Converters
Spring Boot Gradle Plugin
Reactive Flow with MongoDB, Kotlin, and Spring WebFlux
Java Program to Implement LinkedBlockingQueue API
Using a Spring Cloud App Starter
Java Program to Find Minimum Number of Edges to Cut to make the Graph Disconnected
Exploring the Spring 5 WebFlux URL Matching
Introduction to the Functional Web Framework in Spring 5
JUnit 5 @Test Annotation
Java Program to Test Using DFS Whether a Directed Graph is Weakly Connected or Not
Java Program to Compute the Area of a Triangle Using Determinants
Java Program to Repeatedly Search the Same Text (such as Bible by building a Data Structure)
Tránh lỗi ConcurrentModificationException trong Java như thế nào?