Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Introduction

Finding the index of an element from a data structure is a common task for developers. In this tutorial, we’ll use the Java Stream API and third-party libraries to find the index of the first element in a List that matches a boolean condition.

2. Setup

In this article, we’ll write a few test cases using the User object mentioned below to achieve our goal:

public class User {

    private String userName;
    private Integer userId;

   // constructor and getters
}

Moreover, we’ll create an ArrayList of the User object to use in all test cases. After that, we’ll find the index of the first user, whose name is “John”:

List<User> userList = List.of(new User(1, "David"), new User(2, "John"), new User(3, "Roger"), new User(4, "John"));

String searchName = "John";

3. Using Java Stream API

The Java Stream API was one of the best features introduced in Java 8. It provides numerous methods to iterate, filter, map, match, and collect the data. With this in mind, let’s use these methods to find an index from a List.

3.1. Using stream() and filter()

Let’s write a test case using the basic functions of the Stream class in order to obtain an index:

@Test
public void whenUsingStream_thenFindFirstMatchingUserIndex() {
    AtomicInteger counter = new AtomicInteger(-1);
    int index = userList.stream()
      .filter(user -> {
          counter.getAndIncrement();
          return searchName.equals(user.getUserName());
      })
      .mapToInt(user -> counter.get())
      .findFirst()
      .orElse(-1);

    assertEquals(1, index);
}

Here, we can create a Stream from the List and apply a filter() method. Inside the filter() method, we increment the AtomicInteger to track the element’s index. To finish, we map the counter value and use the findFirst() method to get the index of the first matched element.

3.2. Using IntStream

Alternatively, we can use the IntStream class to iterate over List elements and get the index using similar logic as mentioned in the above section:

@Test
public void whenUsingIntStream_thenFindFirstMatchingUserIndex() {
    int index = IntStream.range(0, userList.size())
      .filter(streamIndex -> searchName.equals(userList.get(streamIndex).getUserName()))
      .findFirst()
      .orElse(-1);
    assertEquals(1, index);
}

3.3. Using Stream takeWhile()

The takeWhile() method returns the data until the predicate remains true. However, once the predicate fails, it stops the iteration to collect the iterated data:

@Test
public void whenUsingTakeWhile_thenFindFirstMatchingUserIndex() {
    long predicateIndex = userList.stream()
      .takeWhile(user -> !user.getUserName().equals(searchName))
      .count();
    assertEquals(1, predicateIndex);
}

The example above shows that the takeWhile() method collects elements until a User object named “John” is found and then stops the iteration. After that, we can use the count() method to get the index of the first matched element.

Let’s take another case where there is no matching element present in the list. In this case, the iteration continues till the last element, and the output value is 4, which is the total iterated elements from the input list:

@Test
public void whenUsingTakeWhile_thenFindIndexFromNoMatchingElement() {
    long predicateIndex = userList.stream()
      .takeWhile(user -> !user.getUserName().equals(searchName))
      .count();
    assertEquals(4, predicateIndex);
}

The takeWhile() method was introduced in Java 9.

4. Using Third-Party Libraries

Though the Java Stream API is sufficient to achieve our goal, it’s only available from the Java 1.8 version. If the application is on an older version of Java, then external libraries become useful.

4.1. Iterables From Google Guava

We’ll add the latest Maven dependency to pom.xml:

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

The Iterables class from Guava Library has a method named indexOf(), which returns the index of the first element in the specified iterable that matches the given predicate:

@Test
public void whenUsingGoogleGuava_thenFindFirstMatchingUserIndex() {
    int index = Iterables.indexOf(userList, user -> searchName.equals(user.getUserName()));
    assertEquals(1, index);
}

4.2. IterableUtils From Apache Common Collections

Similarly, the IterableUtils class from the Apache Common Collections library also provides functionalities to obtain an index. Let’s add the Maven dependency in pom.xml:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.4</version>
</dependency>

The IterableUtils.indexOf() method accepts an iterable collection and a predicate and then returns the index of the first matching element:

@Test
public void whenUsingApacheCommons_thenFindFirstMatchingUserIndex() {
    int index = IterableUtils.indexOf(userList, user -> searchName.equals(user.getUserName()));
    assertEquals(1, index);
}

The indexOf() method in both libraries returns -1 if no element meets the predicate criteria.

5. Conclusion

In this article, we learned different ways to find the index of the first element in a List that matches a boolean condition. We used the Java Stream API, the Iterables class from Google Guava, and the IterableUtils class from Apache Commons Collections.

As always, the reference code is available over on GitHub.

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
3 Comments
Oldest
Newest
Inline Feedbacks
View all comments
Comments are closed on this article!