Java 8 поток peek и ограничение взаимодействия
Почему этот код в java 8:
IntStream.range(0, 10)
.peek(System.out::print)
.limit(3)
.count();
выходы:
012
Я ожидаю, что он выведет 0123456789, потому что peek предел предел.
Мне кажется еще более своеобразным из-за того, что это:
IntStream.range(0, 10)
.peek(System.out::print)
.map(x -> x * 2)
.count();
выводит 0123456789, как ожидалось (не 02481012141618).
P.S.: .count()
здесь используется только для потребления потока, его можно заменить чем-нибудь еще
Ответы
Ответ 1
Из docs:
limit()
является short-circuiting stateful intermediate operation.
map()
является intermediate operation
Снова из docs то, что по существу означает, означает, что limit()
вернет поток с x
значениями из потока it получен.
Промежуточная операция является короткозамкнутой, если при представлении с бесконечным входом в результате может образоваться конечный поток.
Ответ 2
Самое важное, что нужно знать о потоках, это то, что они не содержат самих элементов (например, коллекции), но работают как труба, значения которого оцениваются лениво. Это означает, что операторы, которые создают поток, включая отображение, фильтрацию и т.д., Не оцениваются до тех пор, пока не будет выполнена операция терминала.
В первом примере поток пытается подсчитать от 0 до 9, по одному при каждом выполнении следующего действия:
- распечатать значение
- проверить, прошли ли 3 значения (если да, завершение)
Итак, вы действительно получаете вывод 012
.
В вашем втором примере поток снова рассчитывается от 0 до 9, по одному при каждом выполнении следующего действия:
- распечатать значение
- сопоставление x с x * 2, таким образом пересылка двойного значения на следующий шаг
Как вы можете видеть, результат выводится перед отображением, и вы получаете результат 0123456789
. Попробуйте переключить вызовы peek
и map
. Затем вы получите ожидаемый результат.
Ответ 3
Stream
определены для ленивой обработки. Поэтому для завершения вашей операции count()
не нужно смотреть на другие элементы. В противном случае он будет разбит, поскольку limit(…)
определяется как надлежащий способ обработки бесконечных потоков за конечное время (не обрабатывая более чем limit
элементов).
В принципе, можно было бы выполнить свой запрос, даже не глядя на значения int
вообще, так как цепочка операций limit(3).count()
не нуждается в обработке предыдущих операций (кроме проверки того, имеет ли поток наименьшее 3
элементов).
Ответ 4
Потоки используют ленивую оценку, промежуточные операции, то есть peek(), не выполняются до запуска операции терминала.
Для экземпляров следующий код просто напечатает 1. Фактически, как только первый элемент потока 1 достигнет операции терминала, findAny(), выполнение потока будет завершено.
Arrays.asList(1,2,3)
.stream()
.peek(System.out::print)
.filter((n)->n<3)
.findAny();
Viceversa, в следующем примере, будет напечатано 123. Фактически, операция терминала, noneMatch(), должна оценивать все элементы потока, чтобы убедиться, что нет совпадения с его Predicate: n > 4
Arrays.asList(1, 2, 3)
.stream()
.peek(System.out::print)
.noneMatch(n -> n > 4);