How to Iterate Over a Stream With Indices – 如何用指数对流进行迭代

最后修改: 2017年 9月 7日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

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.

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

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

在这篇短文中,我们将看看如何使用IntStream、StreamUtils、EntryStream、和VavrStream来迭代一个Stream

2. Using Plain Java

2.使用普通的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.

我们可以使用Integer范围浏览Stream,还可以从原始元素在数组或集合中通过索引访问这一事实中受益。

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

3.使用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).

另一种用索引迭代的方法可以使用StreamUtilszipWithIndex()方法,该方法来自proton-pack库(最新版本可以在这里)。

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

首先,你需要把它添加到你的 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

4.使用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:

我们也可以使用StreamEx库中EntryStream类的filterKeyValue()进行索引迭代(最新版本可以在这里)。首先,我们需要把它添加到我们的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

5.使用VavreStream进行迭代

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

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

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.

如果你想了解更多关于Vavr的信息,请查看这篇文章

6. Conclusion

6.结论

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 Baeldung.

Java 8 Streams 中包含了很多功能,其中一些已经在Baeldung上介绍过了。

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

这里解释的所有例子的代码,以及更多的代码都可以在GitHub上找到