1. 概述
对于开发者来说,从数据结构中查找元素的索引是一项常见任务。本教程将使用Java 8流API和第三方库,通过一个布尔条件找到列表中的第一个匹配元素的索引。
2. 准备工作
在本文中,我们将使用下面提到的User
对象编写一些测试用例来达到目标:
public class User {
private String userName;
private Integer userId;
// constructor and getters
}
此外,我们将创建一个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. 使用Java流API
Java流API是Java 8引入的优秀特性之一。它提供了众多方法来迭代、过滤、映射、匹配和收集数据。考虑到这一点,我们将利用这些方法从列表中查找索引。
3.1. 使用stream()
和filter()
让我们使用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);
}
在这里,我们可以从列表创建一个流,并应用filter()
方法。在filter()
方法内部,我们使用AtomicInteger
递增计数器来追踪元素的索引。最后,我们将计数器值映射并使用findFirst()
方法获取第一个匹配元素的索引。
3.2. 使用IntStream
另一种选择是使用IntStream
类遍历列表元素,使用上述章节中提到的类似逻辑来获取索引:
@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. 使用Stream takeWhile()
takeWhile()
方法返回直到给定条件为true
的数据。一旦条件失败,它会停止迭代以收集迭代到的数据:
@Test
public void whenUsingTakeWhile_thenFindFirstMatchingUserIndex() {
long predicateIndex = userList.stream()
.takeWhile(user -> !user.getUserName().equals(searchName))
.count();
assertEquals(1, predicateIndex);
}
上述示例显示,takeWhile()
方法收集元素,直到找到名为“John”的User
对象,然后停止迭代。之后,我们可以使用count()
方法获取第一个匹配元素的索引。
在没有匹配元素的情况下,例如列表中不存在匹配项,迭代将继续到最后一个元素,输出值为4,即从输入列表中迭代的总元素数量:
@Test
public void whenUsingTakeWhile_thenFindIndexFromNoMatchingElement() {
long predicateIndex = userList.stream()
.takeWhile(user -> !user.getUserName().equals(searchName))
.count();
assertEquals(4, predicateIndex);
}
takeWhile()
方法是在Java 9中引入的。
4. 使用第三方库
尽管Java流API足以实现我们的目标,但它仅从Java 1.8版本开始可用。如果应用程序在较旧的Java版本上运行,那么外部库就变得很有用。
4.1. Google Guava的Iterables
我们需要在pom.xml
中添加最新的Maven依赖:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.0.0-jre</version>
</dependency>
Guava库中的Iterables
类有一个名为indexOf()
的方法,该方法返回指定可迭代对象中第一个满足给定谓词的元素的索引:
@Test
public void whenUsingGoogleGuava_thenFindFirstMatchingUserIndex() {
int index = Iterables.indexOf(userList, user -> searchName.equals(user.getUserName()));
assertEquals(1, index);
}
4.2. Apache Commons Collections的IterableUtils
同样,Apache Commons Collections库中的IterableUtils
类也提供了获取索引的功能。我们在pom.xml
中添加Apache Commons Collections的Maven依赖:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.5.0-M2</version>
</dependency>
IterableUtils.indexOf()
方法接受一个可迭代集合和一个谓词,然后返回第一个匹配元素的索引:
@Test
public void whenUsingApacheCommons_thenFindFirstMatchingUserIndex() {
int index = IterableUtils.indexOf(userList, user -> searchName.equals(user.getUserName()));
assertEquals(1, index);
}
两个库中的indexOf()
方法如果没有元素满足谓词条件,则返回-1。
5. 总结
在这篇文章中,我们学习了多种方法,用于在列表中查找满足布尔条件的第一个元素的索引。我们使用了Java流API、Google Guava的Iterables
类以及Apache Commons Collections的IterableUtils
类。
最后文本参考代码可在GitHub上找到。