如何使用索引迭代流

2023/05/31

1. 概述

Java 8 Streams不是集合,不能使用它们的索引访问元素,但仍然有一些技巧可以实现这一点。

在这篇简短的文章中,我们将了解如何使用IntStream、StreamUtils、EntryStream和Vavr的Stream迭代Stream。

2. 使用纯Java

我们可以使用Integer范围在Stream中导航,并且还受益于原始元素位于数组或索引可访问的集合中这一事实。

让我们实现一个迭代索引的方法并演示这个方法。简单地说,我们希望得到一个字符串数组,并且只选择偶数索引的元素:

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

下面测试一下我们的实现:

@Test
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. 使用StreamUtils

另一种迭代索引的方法可以使用proton-pack库中StreamUtils的zipWithIndex()方法来完成(最新版本可以在[这里](https://search.maven.org/classic/#search gav 1 g%3A”com.codepoetics” AND a%3A”protonpack”)找到)。

首先,你需要将它添加到你的pom.xml中:

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

现在,让我们看一下代码:

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

下面测试此方法并成功通过:

@Test
void givenList_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. 使用StreamEx

我们还可以使用StreamEx库中EntryStream类的filterKeyValue()来迭代索引(最新版本可以在这里找到[)](https://search.maven.org/classic/#search gav 1 g%3A”one.util” AND a%3A”streamex”)。首先,我们需要将它添加到我们的pom.xml中:
<dependency>
    <groupId>one.util</groupId>
    <artifactId>streamex</artifactId>
    <version>0.6.5</version>
</dependency>

让我们使用前面的示例看一下此方法的简单应用:

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

然后使用类似的测试来对此进行测试:

@Test
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. 使用Vavr的流进行迭代

另一种合理的迭代方式是使用Vavr(以前称为Javaslang)的Stream实现的zipWithIndex()方法:

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

我们可以使用以下方法测试此示例:

@Test
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);
}

如果你想阅读有关Vavr的更多信息,请查看这篇文章

6. 总结

在本快速教程中,我们介绍了四种使用索引迭代流的方法。流得到了很多关注,并且能够使用索引遍历它们可能会有所帮助。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章