Как перебрать поток с индексами

Как перебрать поток с индексами

1. обзор

Java 8Streamsне являются коллекциями, и к элементам нельзя получить доступ с помощью их индексов, но есть еще несколько уловок, чтобы сделать это возможным.

В этой короткой статье мы рассмотрим, как перебиратьStream, используяIntStream,StreamUtils, EntryStream, иVavr‘sStream.

2. Использование простой Java

Мы можем перемещаться поStream, используя диапазонInteger, а также извлекать выгоду из того факта, что исходные элементы находятся в массиве или коллекции, доступной по индексам.

Давайте реализуем метод, который выполняет итерацию с индексами и демонстрирует этот подход.

Проще говоря, мы хотим получить массив изStrings и выбирать только даже проиндексированные элементы:

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

    return evenIndexedNames;
}

Давайте теперь протестируем реализацию:

@Test
public void whenCalled_thenReturnListOfEvenIndexedStrings() {
    String[] names
      = {"Afrim", "Bashkim", "Besim", "Lulzim", "Durim", "Shpetim"};
    List expectedResult
      = Arrays.asList("Afrim", "Besim", "Durim");
    List actualResult
      = StreamIndices.getEvenIndexedStrings(names);

    assertEquals(expectedResult, actualResult);
}

3. ИспользуяStreamUtils

Другой способ итерации с индексами может быть выполнен с использованием методаzipWithIndex() дляStreamUtils из библиотекиproton-pack (последнюю версию можно найтиhere).

Во-первых, вам нужно добавить его в свойpom.xml:


    com.codepoetics
    protonpack
    1.13

Теперь посмотрим на код:

public List> getEvenIndexedStrings(List names) {
    List> list = StreamUtils
      .zipWithIndex(names.stream())
      .filter(i -> i.getIndex() % 2 == 0)
      .collect(Collectors.toList());

    return list;
}

Следующие тесты этот метод и успешно проходит:

@Test
public void whenCalled_thenReturnListOfEvenIndexedStrings() {
    List names = Arrays.asList(
      "Afrim", "Bashkim", "Besim", "Lulzim", "Durim", "Shpetim");
    List> expectedResult = Arrays.asList(
      Indexed.index(0, "Afrim"),
      Indexed.index(2, "Besim"),
      Indexed.index(4, "Durim"));
    List> actualResult
      = StreamIndices.getEvenIndexedStrings(names);

    assertEquals(expectedResult, actualResult);
}

4. ИспользуяStreamEx

Мы также можем выполнять итерацию с индексами, используяfilterKeyValue() классаEntryStream из библиотекиStreamEx (последнюю версию можно найтиhere). Во-первых, нам нужно добавить его в нашpom.xml:


    one.util
    streamex
    0.6.5

Давайте посмотрим на простое применение этого метода на нашем предыдущем примере:

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

Мы воспользуемся аналогичным тестом, чтобы проверить это:

@Test
public void whenCalled_thenReturnListOfEvenIndexedStringsVersionTwo() {
    String[] names
      = {"Afrim", "Bashkim", "Besim", "Lulzim", "Durim", "Shpetim"};
    List expectedResult
      = Arrays.asList("Afrim", "Besim", "Durim");
    List actualResult
      = StreamIndices.getEvenIndexedStrings(names);

   assertEquals(expectedResult, actualResult);
}

5. Итерация с использованием Vavre‘sStream

Другой вероятный способ итерации - использование методаzipWithIndex() из реализацииVavr (ранее известного какJavaslang) sStream:

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

Мы можем проверить этот пример с помощью следующего метода:

@Test
public void whenCalled_thenReturnListOfOddStringsVersionTwo() {
    String[] names
      = {"Afrim", "Bashkim", "Besim", "Lulzim", "Durim", "Shpetim"};
    List expectedResult
      = Arrays.asList("Bashkim", "Lulzim", "Shpetim");
    List actualResult
      = StreamIndices.getOddIndexedStringsVersionTwo(names);

    assertEquals(expectedResult, actualResult);
}

Если вы хотите узнать больше о Vavr,check this article.

6. Заключение

В этом быстром уроке мы увидели четыре подхода к тому, как перебирать потоки, используя индексы. Потоки привлекли большое внимание, и может быть полезна возможность их перебирать с помощью индексов.

В Java 8 Streams включено множество функций, некоторые из которых уже включены вexample.

Код для всех описанных здесь примеров и многое другое можно найти вover on GitHub.