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);