1. Introduction
1.导言
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.
查找数据结构中元素的索引是开发人员的一项常见任务。在本教程中,我们将使用 Java Stream API 和第三方库查找 List 中符合布尔条件的第一个元素的索引。
2. Setup
2.设置
In this article, we’ll write a few test cases using the User object mentioned below to achieve our goal:
在本文中,我们将使用下面提到的 User 对象编写几个测试用例,以实现我们的目标:
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”:
此外,我们将创建一个 ArrayList 的 User 对象,以便在所有测试用例中使用。然后,我们将找到第一个用户的索引,他的名字是 “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
3.使用 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.
Java Stream API 是 Java 8 中引入的最佳功能之一。它提供了许多方法来遍历、过滤、映射、匹配和收集数据。有鉴于此,让我们使用这些方法从 List 中查找索引。
3.1. Using stream() and filter()
3.1.使用 stream() 和 filter()
Let’s write a test case using the basic functions of the Stream class in order to obtain an index:
让我们使用 Stream 类的基本功能编写一个测试用例,以获取索引:
@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.
在这里,我们可以从 List 创建一个 Stream 并应用 filter() 方法。在 filter() 方法中,我们会递增 AtomicInteger 以跟踪元素的索引。最后,我们映射计数器值,并使用 findFirst() 方法获取第一个匹配元素的索引。
3.2. Using IntStream
3.2.使用 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:
或者,我们可以使用 IntStream 类遍历 List 元素,并使用上一节中提到的类似逻辑获取索引:
@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()
3.3.使用 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:
takeWhile() 方法会返回数据,直到谓词保持true为止。但是,一旦谓词失败,就会停止迭代以收集迭代数据:
@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.
上例显示,takeWhile() 方法收集元素,直到找到名为 “John” 的 User 对象,然后停止迭代。之后,我们可以使用 count() 方法获取第一个匹配元素的索引。
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:
我们再来看看列表中没有匹配元素的情况。在这种情况下,迭代将持续到最后一个元素,输出值为 4, 即输入列表中被迭代的元素总数:
@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.
takeWhile()方法是在Java 9中引入的。
4. Using Third-Party Libraries
4.使用第三方库
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.
虽然 Java Stream API 足以实现我们的目标,但它仅适用于 Java 1.8 版本。如果应用程序使用的是旧版本的 Java,那么外部库就会变得非常有用。
4.1. Iterables From Google Guava
4.1.Iterables 来自 Google Guava
We’ll add the latest Maven dependency to pom.xml:
我们将在 pom.xml 中添加最新的 Maven 依赖关系:
<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:
Guava 库中的 Iterables 类有一个名为 indexOf() 的方法, 该方法返回指定 iterable 中第一个匹配给定谓词的元素的索引:
@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
4.2.IterableUtils 来自 Apache 通用集合
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:
同样,Apache 通用集合库中的 IterableUtils 类也提供了获取索引的功能。让我们在 pom.xml 中添加 Maven 依赖关系:
<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:
IterableUtils.indexOf() 方法接受一个可迭代集合和一个谓词,然后返回第一个匹配元素的索引:
@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.
如果没有元素符合谓词条件,两个库中的 indexOf() 方法都会返回 -1 。
5. Conclusion
5.结论
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.
在本文中,我们学习了查找 List 中符合布尔条件的第一个元素的索引的不同方法。我们使用了 Java Stream API、Google Guava 中的 Iterables 类和 Apache Commons Collections 中的 IterableUtils 类。
As always, the reference code is available over on GitHub.
一如既往,您可以在 GitHub 上获取参考代码。