Существует ли потоковая операция Java 8, которая ограничивает a (потенциально бесконечно) Stream до тех пор, пока первый элемент не будет соответствовать предикату?
В Java 9 мы можем использовать takeWhile как в примере ниже, чтобы вывести все числа меньше 10.
IntStream .iterate(1, n -> n + 1) .takeWhile(n -> n < 10) .forEach(System.out::println);
Поскольку в Java 8 такой операции нет, каков наилучший способ реализовать ее в общем виде?
Переведено автоматически
Ответ 1
Операции takeWhile и dropWhile добавлены в JDK 9. Ваш пример кода
IntStream .iterate(1, n -> n + 1) .takeWhile(n -> n < 10) .forEach(System.out::println);
будет вести себя точно так, как вы ожидаете, при компиляции и запуске в JDK 9.
Выпущен JDK 9. Его можно скачать здесь: Выпуски JDK 9.
Ответ 2
Такая операция должна быть возможной с Java 8 Stream, но это не обязательно может быть выполнено эффективно - например, вы не обязательно можете распараллелить такую операцию, поскольку вам нужно смотреть на элементы по порядку.
API не предоставляет простого способа сделать это, но, вероятно, самый простой способ - взять Stream.iterator(), обернуть Iterator, чтобы получить реализацию "take-while", а затем вернуться к Spliterator а затем к Stream. Или - возможно - обернуть Spliterator, хотя на самом деле его больше нельзя разделить в этой реализации.
Вот непроверенная реализация takeWhile на Spliterator:
allMatch() это функция короткого замыкания, поэтому вы можете использовать ее для остановки обработки. Основным недостатком является то, что вам приходится выполнять тест дважды: один раз, чтобы увидеть, следует ли его обрабатывать, и еще раз, чтобы увидеть, стоит ли продолжать.
IntStream .iterate(1, n -> n + 1) .peek(n->{if (n<10) System.out.println(n);}) .allMatch(n->n < 10);
Ответ 4
В качестве продолжения ответа @StuartMarks. Моя библиотека StreamEx имеет takeWhile операцию, совместимую с текущей реализацией JDK-9. При запуске под JDK-9 он будет просто делегирован реализации JDK (через MethodHandle.invokeExact что действительно быстро). При запуске под JDK-8 будет использоваться реализация "polyfill". Итак, используя мою библиотеку, проблему можно решить следующим образом:
IntStreamEx.iterate(1, n -> n + 1) .takeWhile(n -> n < 10) .forEach(System.out::println);