1. Обзор
В этом кратком обзоре мы сосредоточимся на новых интересных улучшениях Stream API, появившихся в Java 9.
2. Стрим Takewhile/Dropwhile
Обсуждения этих методов неоднократно появлялись на StackOverflow (самый популярный — этот ).
Представьте, что мы хотим сгенерировать поток
String
, добавляя один символ к значению предыдущего потока
, пока длина текущего значения в этом потоке
не станет меньше 10
.
Как бы мы решили это в Java 8? Мы могли бы использовать одну из укорачивающих промежуточных операций, таких как limit
, allMatch
, которые на самом деле служат для других целей, или написать собственную реализацию takeWhile
на основе Spliterator
, что, в свою очередь, усложняет такую простую задачу.
С Java 9 решение простое:
Stream<String> stream = Stream.iterate("", s -> s + "s")
.takeWhile(s -> s.length() < 10);
Операция takeWhile
принимает предикат
, который применяется к элементам для определения самого длинного префикса этих элементов (если поток упорядочен) или подмножества элементов потока (если поток неупорядочен).
Чтобы двигаться дальше, нам нужно лучше понять, что означают термины «самый длинный префикс» и «подмножество потока »:
- самый длинный префикс — это непрерывная последовательность элементов потока, соответствующих заданному предикату. Первый элемент последовательности является первым элементом этого потока, а элемент, непосредственно следующий за последним элементом последовательности, не соответствует заданному предикату.
- подмножество
потока
— это набор некоторых (но не всех) элементовпотока
, соответствующих заданному предикату.
После введения этих ключевых терминов мы можем легко понять еще одну новую операцию dropWhile
.
Он делает прямо противоположное takeWhile
. Если поток упорядочен, то dropWile
возвращает поток, состоящий из оставшихся элементов этого потока
после отбрасывания самого длинного префикса элементов, соответствующих заданному предикату.
В противном случае, если Stream
неупорядочен, dropWile
возвращает поток, состоящий из оставшихся элементов этого Stream
после отбрасывания подмножества элементов, соответствующих заданному предикату.
Давайте отбросим первые пять элементов, используя полученный ранее Stream
:
stream.dropWhile(s -> !s.contains("sssss"));
Проще говоря, операция dropWhile
удалит элементы, в то время как заданный предикат для элемента возвращает true
и прекращает удаление при первом предикате false
.
3. Потоковая итерация
Следующей новой функцией является перегруженный метод итерации
для генерации конечных потоков
. Не путать с конечным
вариантом, который возвращает бесконечный последовательный упорядоченный поток
, созданный некоторой функцией.
Новая итерация
слегка модифицирует этот метод, добавляя предикат, который применяется к элементам, чтобы определить, когда поток должен завершиться. Его использование очень удобно и лаконично:
Stream.iterate(0, i -> i < 10, i -> i + 1)
.forEach(System.out::println);
Его можно связать с соответствующим оператором for :
for (int i = 0; i < 10; ++i) {
System.out.println(i);
}
4. Поток Nullable
Бывают ситуации, когда нам нужно поместить элемент в поток
. Иногда этот элемент может быть нулевым
, но мы не хотим, чтобы наш Stream
содержал такие значения. Это приводит к написанию либо оператора if
, либо тернарного оператора, который проверяет, является ли элемент нулевым.
Предполагая, что переменные коллекции
и карты
были созданы и заполнены успешно, взгляните на следующий пример:
collection.stream()
.flatMap(s -> {
Integer temp = map.get(s);
return temp != null ? Stream.of(temp) : Stream.empty();
})
.collect(Collectors.toList());
Чтобы избежать такого шаблонного кода, в класс Stream
был добавлен метод ofNullable
. С помощью этого метода предыдущий образец можно просто преобразовать в: ``
collection.stream()
.flatMap(s -> Stream.ofNullable(map.get(s)))
.collect(Collectors.toList());
5. Вывод
Мы рассмотрели основные изменения Stream API в Java 9 и то, как эти улучшения помогут нам писать более выразительные программы с меньшими усилиями.
Как всегда, фрагменты кода можно найти на Github .