Как выполнить итерацию по потоку с индексами

В отличие от элементов Collection, к элементам Stream нельзя получить доступ через индексы, но все еще есть обходные пути для получения индексов элементов. В этом уроке Java мы изучим несколько способов итерации по Stream с индексами.

1. Настройка

В демонстрационных целях мы используем следующий класс Employee.

public class Employee {private String name;private String email;private int age;}

И мы также инициализируем массив новых объектов сотрудников, который преобразуем в поток, а затем отфильтруем его по индексам:

Employee[] employees = {new Employee("Alexandru", "alexandru@gmail.com", 22),new Employee("Emanuela", "ema@gmail.com", 20),new Employee("George", "george@gmail.com", 32),new Employee("John", "john123@gmail.com", 25),new Employee("Liam", "liam123@gmail.com", 45),new Employee("Noah", "noah@outlook.com", 30),new Employee("Oliver", "oliver@yahoo.com", 47)};

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

Для нашего первого примера мы воспользуемся тем фактом, что к нашим элементам массива можно получить доступ через индексы. Поэтому, принимая это в некотором смысле, мы будем использовать класс IntStream для итерации чисел от 0 до длины нашего массива, фильтровать их по индексу и сопоставлять их с соответствующими объектами Employee для желаемых индексов.

Мы также можем собрать экземпляры сотрудников в новом списке, если существует такое требование.

IntStream.range(0, employees.length).filter(i -> i % 2 == 0).mapToObj(i -> employees[i]).forEach(System.out::println);

Мы также можем использовать AtomicInteger для хранения индекса элементов потока. Затем мы получим поток из массива с помощью функции stream() и сопоставим каждый элемент потока с индексом с помощью метода map(), где индекс извлекается из AtomicInteger путем инкрементирования каждый раз с помощью функции getAndIncrement().

AtomicInteger index = new AtomicInteger();Arrays.stream(employees).map(i -> index.getAndIncrement()).filter(i -> i % 2 == 0).map(i -> employees[i]).forEach(System.out::println);

3. Использование StreamUtils

В этом примере мы будем использовать класс StreamUtils из библиотеки protonpack.

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

Теперь мы можем использовать функцию zipWithIndex() из класса StreamUtils. Эта функция возьмет элементы и сожмет каждое значение с его индексом, чтобы создать поток индексированных значений. После вызова функции мы отфильтруем элементы по их индексу, сопоставим их со значением и выведем каждый элемент.

StreamUtils.zipWithIndex(Arrays.stream(employees)).filter(e -> e.getIndex() % 2 == 0).map(e -> e.getValue()).forEach(System.out::println);

3. Использование StreamEx

Теперь мы будем использовать класс EntryStream из библиотеки StreamEx.

<dependency><groupId>one.util</groupId><artifactId>streamex</artifactId><version>0.8.1</version></dependency>

Теперь мы можем использовать метод filterKeyValue() для фильтрации наших значений по их индексу. После этого мы возьмем только значения и выведем их на консоль.

EntryStream.of(employees).filterKeyValue((index, name) -> index % 2 == 0).values().forEach(System.out::println);

4. Использование потоков Guava

Guava — это группа основных библиотек Java от Google, которая содержит новые классы коллекций(такие как multimap и multiset) и многое другое! Она широко используется в большинстве проектов Java в Google и во многих других компаниях.

 <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>31.0.1-jre</version></dependency>

Мы будем использовать функцию mapWithIndex(), которая возвращает поток, содержащий результаты применения данной функции к элементам потока и их индексам в потоке. После применения функции мы вернем нулевые значения для нечетных индексов, отфильтруем их и выведем результат.

Streams.mapWithIndex(Arrays.stream(employees),(emp, index) -> index % 2 ==0 ? emp : null).filter(emp -> emp != null).forEach(System.out::println); 

5. Итерация с использованием потока Вавра

Vavr — функциональная библиотека для Java. Позволяет сократить объем кода и повысить надежность.

<dependency><groupId>io.vavr</groupId><artifactId>vavr</artifactId><version>0.10.4</version></dependency>

Теперь мы можем использовать функцию zipWithIndex(), которая будет проходить по нашему потоку и возвращать кортеж, содержащий значение и индекс значения. Теперь мы можем легко отфильтровать элементы на основе четности индекса и вывести его на консоль.

Stream.of(employees).zipWithIndex().filter(tuple -> tuple._2 % 2 == 0).map(tuple -> tuple._1).forEach(System.out::println);

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

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

Прокрутить вверх