1. Обзор
API Java Stream
был основной функцией выпуска Java 8. Потоки
представляют собой последовательности объектов с ленивой оценкой и предоставляют богатый, плавный и похожий на монадический API.
В этой статье мы кратко рассмотрим способы получения последнего элемента потока.
Имейте в виду, что из-за природы потоков это не естественная операция . Всегда убедитесь, что вы не работаете с бесконечными потоками.
2. Использование API сокращения
Проще говоря, Reduce
уменьшает набор элементов в потоке
до одного элемента.
В этом случае мы уменьшим набор элементов, чтобы получить последний элемент в потоке.
Имейте в виду, что этот метод будет возвращать детерминированные результаты только для последовательных потоков.
Давайте воспользуемся списком
строковых
значений , получим поток
из списка
и затем уменьшим:
List<String> valueList = new ArrayList<>();
valueList.add("Joe");
valueList.add("John");
valueList.add("Sean");
Stream<String> stream = valueList.stream();
stream.reduce((first, second) -> second)
.orElse(null);
Здесь поток сокращается до уровня, на котором остается только последний элемент. Если поток пуст, он вернет нулевое
значение.
2. Использование функции пропуска
Другой способ получить последний элемент потока — пропустить все элементы перед ним . Этого можно добиться с помощью функции Skip класса
Stream
. Имейте в виду, что в данном случае поток
используется дважды, поэтому производительность заметно снижается .
Давайте создадим список
строковых значений и используем его функцию размера
, чтобы определить, сколько элементов нужно пропустить, чтобы достичь последнего элемента.
Вот пример кода, получающего последний элемент с помощью skip
:
List<String> valueList = new ArrayList<String>();
valueList.add("Joe");
valueList.add("John");
valueList.add("Sean");
long count = valueList.stream().count();
Stream<String> stream = valueList.stream();
stream.skip(count - 1).findFirst().get();
«Шон»
оказывается последним элементом.
4. Получение последнего элемента бесконечного потока
Попытка получить последний элемент бесконечного потока привела бы к бесконечной последовательности вычислений, выполняемых для бесконечных элементов. Как skip
, так и reduce
не вернутся из выполнения оценки, если мы не ограничим бесконечный поток определенным количеством элементов, используя операцию ограничения .
Вот пример кода, где мы взяли бесконечный поток и попытались получить последний элемент:
Stream<Integer> stream = Stream.iterate(0, i -> i + 1);
stream.reduce((first, second) -> second).orElse(null);
Следовательно, поток не вернется из оценки и в конечном итоге остановит выполнение программы .
5. Вывод
Мы видели разные способы получения последнего элемента потока
как с помощью API сокращения
, так и с помощью Skip .
Мы также рассмотрели, почему это невозможно с бесконечными потоками.
Мы видели, что получить последний элемент из Stream
непросто по сравнению с его извлечением из других структур данных. Это связано с ленивым характером потоков
, которые не оцениваются, пока не будет вызвана терминальная функция, и мы никогда не узнаем, является ли текущий оцениваемый элемент последним.
Фрагменты кода можно найти на GitHub.