Перейти к основному содержимому

Усовершенствования потокового API Java 9

· 3 мин. чтения

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 .