1. Обзор
Потоки
в Java 8 не являются коллекциями, и доступ к элементам с помощью их индексов невозможен, но есть несколько приемов, позволяющих сделать это возможным.
В этой короткой статье мы рассмотрим, как перебирать Stream
с помощью IntStream,
StreamUtils,
EntryStream и Stream
Vavr
. ``
2. Использование простой Java
Мы можем перемещаться по потоку
, используя диапазон целых чисел
, а также извлекать выгоду из того, что исходные элементы находятся в массиве или коллекции, доступной по индексам.
Давайте реализуем метод, который перебирает индексы и демонстрирует этот подход.
Проще говоря, мы хотим получить массив строк
и выбрать только четные индексированные элементы:
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;
}
Давайте теперь протестируем реализацию:
@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. Использование StreamUtils
Другой способ перебора с индексами можно выполнить с помощью метода zipWithIndex()
StreamUtils
из библиотеки proton-pack
(последнюю версию можно найти здесь ).
Во-первых, вам нужно добавить его в свой pom.xml
:
<dependency>
<groupId>com.codepoetics</groupId>
<artifactId>protonpack</artifactId>
<version>1.13</version>
</dependency>
Теперь давайте посмотрим на код:
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;
}
Следующие тесты этого метода проходят успешно:
@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. Использование StreamEx
Мы также можем перебирать индексы, используя filterKeyValue()
класса EntryStream
из библиотеки 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
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. Итерация с использованием Vavre
Stream
Другой вероятный способ итерации — использование метода zipWithIndex() реализации
Stream
Vavr
(ранее известного как Javaslang
) : ``
public List<String> 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<String> expectedResult
= Arrays.asList("Bashkim", "Lulzim", "Shpetim");
List<String> actualResult
= StreamIndices.getOddIndexedStringsVersionTwo(names);
assertEquals(expectedResult, actualResult);
}
Если вы хотите узнать больше о Vavr, прочтите эту статью.
6. Заключение
В этом кратком руководстве мы рассмотрели четыре подхода к перебору потоков с использованием индексов. Потоки привлекли много внимания, и возможность перебирать их с помощью индексов может быть полезной.
В Java 8 Streams включено множество функций, некоторые из которых уже описаны в ForEach .
Код для всех описанных здесь примеров и многое другое можно найти на GitHub .