Улучшения API Java 9 Stream

Улучшения API Java 9 Stream

1. обзор

В этой быстрой статье мы сосредоточимся на новых интересных улучшениях Stream API, появившихся в Java 9.

2. Stream Takewhile / Drop while

Обсуждения этих методов неоднократно появлялись наStackOverflow (самый популярный -this one).

Представьте, что мы хотим сгенерироватьStream изStrings, добавив один символ к предыдущему значениюStream, пока длина текущего значения в этомStream не станет меньше, чем 10.

Как бы мы решили это в Java 8? Мы могли бы использовать одну из промежуточных операций короткого замыкания, напримерlimit,allMatch, которые на самом деле служат для других целей, или написать свои собственныеtakeWhile implementation на основеSpliterator, которые, в свою очередь, , усложняет такую ​​простую проблему.

С Java 9 решение легко:

Stream stream = Stream.iterate("", s -> s + "s")
  .takeWhile(s -> s.length() < 10);

ОперацияtakeWhile принимаетPredicate, который применяется к элементам для определения самого длинного префикса этих элементов (если поток упорядочен) или подмножества элементов потока (когда поток неупорядочен).

Чтобы двигаться дальше, нам нужно лучше понять, что означают термины «самый длинный префикс» и «подмножествоStream’s»:

  • the longest prefix - непрерывная последовательность элементов потока, соответствующих данному предикату. Первый элемент последовательности является первым элементом этого потока, и элемент, непосредственно следующий за последним элементом последовательности, не соответствует данному предикату

  • a Stream’s subset - это набор некоторых (но не всех) элементовStream, соответствующих данному предикату.

После введения этих ключевых терминов мы можем легко понять еще одну новую операциюdropWhile.

Он делает прямо противоположноеtakeWhile. Если поток упорядочен,dropWile возвращает поток, состоящий из оставшихся элементов этогоStreamafter dropping the longest prefix элементов, соответствующих данному предикату.

В противном случае, еслиStream неупорядочен,dropWile возвращает поток, состоящий из оставшихся элементов этогоStreamafter dropping a subset элементов, соответствующих данному предикату.

Давайте отбросим первые пять элементов, используя полученный ранееStream:

stream.dropWhile(s -> !s.contains("sssss"));

Проще говоря, операцияdropWhile удаляет элементы, в то время как данный предикат для элемента возвращаетtrue и прекращает удаление наfalse первого предиката.

3. Stream Iterate

Следующая новая функция -the overloaded iterate method for finite Streams generation. Не путать с вариантомfinite, который возвращает бесконечный последовательный упорядоченныйStream, созданный некоторой функцией.

Новыйiterate немного изменяет этот метод, добавляя предикат, который применяется к элементам, чтобы определить, когда поток должен завершиться. Его использование очень удобно и лаконично:

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. Stream Ofnullable

Бывают ситуации, когда нам нужно поместить элемент вStream. Иногда этот элемент может бытьnull, но мы не хотим, чтобы нашStream содержал такие значения. Это вызывает запись либо оператораif, либо тернарного оператора, который проверяет, является ли элементnull.

Предполагая, что переменныеcollection иmap были созданы и успешно заполнены, взгляните на следующий пример:

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 и выяснили, как эти улучшения помогут нам писать более выразительные программы с меньшими усилиями.

Как всегда, фрагменты кода можно найтиover on Github.