Существует ли потоковая операция Java 8, которая ограничивает (потенциально бесконечный) Stream
до тех пор, пока первый элемент не будет соответствовать предикату?
В Java 9 мы можем использовать, takeWhile
как в примере ниже, чтобы напечатать все числа меньше 10.
IntStream
.iterate(1, n -> n + 1)
.takeWhile(n -> n < 10)
.forEach(System.out::println);
Поскольку в Java 8 такой операции нет, каков наилучший способ ее реализации в общем виде?
java
java-8
java-stream
MForster
источник
источник
IntStream.iterate(1, n->n<10, n->n+1).forEach(System.out::print);
Ответы:
Такая операция должна быть возможной с Java 8
Stream
, но она не обязательно может быть выполнена эффективно - например, вы не можете обязательно распараллелить такую операцию, поскольку вы должны смотреть на элементы по порядку.API не предоставляет простой способ сделать это, но, вероятно, самый простой способ - это взять
Stream.iterator()
, обернуть,Iterator
чтобы иметь реализацию "take-while", а затем вернуться к aSpliterator
и затем aStream
. Или - может быть - обернутьSpliterator
, хотя это не может быть больше разделено в этой реализации.Вот непроверенная реализация
takeWhile
наSpliterator
:источник
Операции
takeWhile
иdropWhile
были добавлены в JDK 9. Ваш пример кодабудет вести себя точно так, как вы ожидаете, при компиляции и запуске под JDK 9.
JDK 9 был выпущен. Он доступен для скачивания здесь: http://jdk.java.net/9/
источник
takeWhile
/dropWhile
: download.java.net/jdk9/docs/api/java/util/stream/Stream.htmltakeWhile
и ,dropWhile
а неlimitWhile
иskipWhile
, для обеспечения согласованности с существующими API?takeWhile
иdropWhile
довольно широко распространены, встречаясь в Scala, Python, Groovy, Ruby, Haskell и Clojure. Асимметрия сskip
иlimit
является неудачной. Может быть,skip
иlimit
следовало бы позвонитьdrop
иtake
, но это не так интуитивно, если вы уже не знакомы с Haskell.dropXXX
иtakeXXX
более популярные термины , но я могу лично жить с более SQL-эскlimitXXX
иskipXXX
. Я нахожу эту новую асимметрию намного более запутанной, чем индивидуальный выбор терминов ... :) (кстати, у Scala также естьdrop(int)
иtake(int)
)allMatch()
является функцией короткого замыкания, так что вы можете использовать ее, чтобы остановить обработку. Основным недостатком является то, что вы должны сделать свой тест дважды: один раз, чтобы увидеть, нужно ли его обрабатывать, и еще раз, чтобы увидеть, стоит ли продолжать.источник
Stream.allMatch()
это короткое замыкание . Так что это завершится даже на бесконечном потоке, какIntStream.iterate()
. Конечно, в ретроспективе, это разумная оптимизация.peek
. Если бы я столкнулся с этим в следующем месяце, мне потребовалась бы минутка, чтобы задуматься, почему программист до меня проверял,allMatch
а затем игнорировал ответ.В качестве продолжения ответа @StuartMarks . В моей библиотеке StreamEx есть
takeWhile
операция, совместимая с текущей реализацией JDK-9. При работе под JDK-9 он просто делегирует реализацию JDK (благодаряMethodHandle.invokeExact
которой это действительно быстро). При работе под JDK-8 будет использоваться реализация «polyfill». Таким образом, используя мою библиотеку, проблема может быть решена так:источник
takeWhile
является одной из функций, предоставляемых библиотекой protonpack .источник
Обновление: Java 9
Stream
теперь поставляется с методом takeWhile .Нет необходимости для взлома или других решений. Просто используйте это!
Я уверен, что это может быть значительно улучшено: (кто-то может сделать это потокобезопасным, может быть)
Взломать наверняка ... Не элегантно - но это работает ~: D
источник
Вы можете использовать java8 + rxjava .
источник
На самом деле есть два способа сделать это в Java 8 без каких-либо дополнительных библиотек или с помощью Java 9.
Если вы хотите напечатать числа от 2 до 20 на консоли, вы можете сделать это:
или
Выход в обоих случаях:
Никто не упомянул что- либо еще. Это причина этого поста.
источник
Это источник, скопированный из JDK 9 java.util.stream.Stream.takeWhile (Predicate). Небольшая разница для работы с JDK 8.
источник
Вот версия, сделанная для ints - как задано в вопросе.
Использование:
Вот код для StreamUtil:
источник
Пойдите, чтобы получить библиотеку AbacusUtil . Он предоставляет точный API, который вы хотите, и многое другое:
Декларация: я разработчик AbacusUtil.
источник
Вы не можете прервать поток, за исключением короткого замыкания в терминальной операции, в результате чего некоторые значения потока остаются необработанными независимо от их значения. Но если вы просто хотите избежать операций с потоком, вы можете добавить преобразование и фильтр к потоку:
Это преобразовывает поток вещей в нули, когда вещи удовлетворяют некоторому условию, а затем отфильтровывает нули. Если вы хотите побаловать себя побочными эффектами, вы можете установить значение условия в true, как только что-то встретится, поэтому все последующие вещи будут отфильтрованы независимо от их значения. Но даже если нет, вы можете сохранить большую часть (если не совсем всю) обработку, отфильтровывая значения из потока, который вы не хотите обрабатывать.
источник
Даже у меня было похожее требование - запусти веб-сервис, если не получится, повторите его 3 раза. Если это не удается даже после этих многочисленных испытаний, отправьте уведомление по электронной почте. Погуглив много,
anyMatch()
пришел как спаситель. Мой пример кода выглядит следующим образом. В следующем примере, если метод webServiceCall возвращает true в самой первой итерации, поток не выполняет дальнейшую итерацию, как мы ее вызвалиanyMatch()
. Я считаю, это то, что вы ищете.источник
Если вы знаете точное количество повторений, которые будут выполнены, вы можете сделать
источник
вместо пика вы можете использовать mapToObj для возврата конечного объекта или сообщения
источник
Если у вас другая проблема, может потребоваться другое решение, но для вашей текущей проблемы я бы просто сказал:
источник
Может быть, немного не по теме, но это то, что у нас есть,
List<T>
а неStream<T>
.Для начала вам нужно использовать
take
метод util. Этот метод принимает первыеn
элементы:это просто работает как
scala.List.take
Теперь будет довольно просто написать
takeWhile
метод, основанный наtake
это работает так:
эта реализация частично повторяет список несколько раз, но не добавляет
O(n^2)
операций добавления . Надеюсь, что это приемлемо.источник
У меня есть другое быстрое решение путем реализации этого (который на самом деле нечист, но вы поняли):
источник
current
никогда.equals(e)
, вы получите бесконечный цикл. Оба, даже если вы впоследствии подаете заявку, например.limit(1)
. Это намного хуже, чем «нечисто» .Вот моя попытка использовать только библиотеку Java Stream.
источник
filter
предикат не имеет состояния.System.out.println
это побочный эффект.