https://github.com/yaitskov/j4ts/blob/stream/src/main/java/javaemul/internal/stream/StreamHelper.java

отрим следующий код:

urls.stream()
    .flatMap(url -> fetchDataFromInternet(url).stream())
    .filter(...)
    .findFirst()
    .get();

БудетfetchDataFromInternet вызывать второй URL, когда первого было достаточно?

Я попробовал с меньшим примером, и это похоже на работу, как ожидалось. то есть обрабатывает данные один за другим, но можно ли полагаться на это поведение? Если нет, звонит ли.sequential() до.flatMap(...) Помогите?

    Stream.of("one", "two", "three")
            .flatMap(num -> {
                System.out.println("Processing " + num);
                // return FetchFromInternetForNum(num).data().stream();
                return Stream.of(num);
            })
            .peek(num -> System.out.println("Peek before filter: "+ num))
            .filter(num -> num.length() > 0)
            .peek(num -> System.out.println("Peek after filter: "+ num))
            .forEach(num -> {
                System.out.println("Done " + num);
            });

Выход:

Processing one
Peek before filter: one
Peek after filter: one
Done one
Processing two
Peek before filter: two
Peek after filter: two
Done two
Processing three
Peek before filter: three
Peek after filter: three
Done three

Обновить: Использование официального Oracle JDK8, если это важно для реализации

ОтветНа основании комментариев и ответов ниже, плоская карта частично ленива. Т.е. полностью читает первый поток и только при необходимости он переходит к следующему. Читать поток очень хочется, но читать несколько потоков лениво.

Если это поведение предназначено, API должен позволить функции возвращатьIterable вместо потока.

Другими словами:ссылка

 pedromss19 сент. 2017 г., 01:40
Что заставляет вас думать, что это не так?
 pedromss19 сент. 2017 г., 01:54
@balki SO сообщение, которое вы связали, утверждает в принятом ответе, что промежуточные операции всегда ленивы. Кроме того, издокументация: «Потоки ленивы; вычисления на исходных данных выполняются только тогда, когда инициируется работа терминала, а исходные элементы потребляются только по мере необходимости». Flatmap - это промежуточная операция
 teppic19 сент. 2017 г., 00:33
Документ опараллелизм говорит "Когда вы создаете поток, это всегда последовательный поток, если не указано иное.", поэтому вызов.sequential() не обязательно
 Holger19 сент. 2017 г., 09:17
fetchDataFromInternet не будет вызываться больше, чем необходимо, но элементы, возвращаемые определеннымfetchDataFromInternet вызов может быть обработан без лени.
 balki19 сент. 2017 г., 01:51
Документация @pedromss не говорит об этом явно.docs.oracle.com/javase/8/docs/api/java/util/stream/... И, похоже, есть несколько случаев, когда это может быть не ленивым:stackoverflow.com/questions/29229373/...

Ответы на вопрос(3)

почему вы создали пример, который не затрагивает фактический вопрос, который вас интересует. Если вы хотите знать, является ли обработка ленивой при применении операции короткого замыкания, такой какfindFirst()ну, тогда используйте пример, используяfindFirst() вместоforEach это обрабатывает все элементы в любом случае. Кроме того, поместите оператор регистрации прямо в функцию, оценку которой вы хотите отслеживать:

Stream.of("hello", "world")
      .flatMap(s -> {
          System.out.println("flatMap function evaluated for \""+s+'"');
          return s.chars().boxed();
      })
      .peek(c -> System.out.printf("processing element %c%n", c))
      .filter(c -> c>'h')
      .findFirst()
      .ifPresent(c -> System.out.printf("found an %c%n", c));
flatMap function evaluated for "hello"
processing element h
processing element e
processing element l
processing element l
processing element o
found an l

Это показывает, что функция переданаflatMap оценивается лениво, как и ожидалось, в то время как элементы возвращаемого (под) потока не оцениваются настолько лениво, насколько это возможно, как уже обсуждалось вQ & A Вы связали себя.

Итак, относительно вашегоfetchDataFromInternet метод, который вызывается из функции, переданнойflatMapВы получите желаемую лень. Но не для данных, которые он возвращает.

но, потому что простой случай, как показано ниже, работает нормально, но подобный производственный код не работает.

 stream(spliterator).map(o -> o).flatMap(Stream::of)..flatMap(Stream::of).findAny()

Для парней, которые не могут ждать еще пару лет для перехода на JDK-10, есть альтернативный истинный ленивый поток. Он не поддерживает параллель. Он был предназначен для перевода JavaScript, но у меня все получилось, потому что интерфейс такой же.

StreamHelper основан на коллекциях, но Spliterator легко адаптировать.

https://github.com/yaitskov/j4ts/blob/stream/src/main/java/javaemul/internal/stream/StreamHelper.java

Решение Вопроса

В рамках текущей реализации, flatmap жаждет; как и любая другая промежуточная операция с состоянием (например,sorted а такжеdistinct). И это очень легко доказать:

             .flatMap(x -> Stream.generate(() -> ThreadLocalRandom.current().nextInt()))
            .findFirst()
            .get();

    System.out.println(result);

Это никогда не заканчивается какflatMap рассчитывается с нетерпением. Для вашего примера:

urls.stream()
    .flatMap(url -> fetchDataFromInternet(url).stream())
    .filter(...)
    .findFirst()
    .get();

Это означает, что для каждогоurl,flatMap заблокирует все остальные операции, которые последуют за ним, даже если вы заботитесь об одной. Итак, давайте предположим, что из одногоurl твойfetchDataFromInternet(url) генерирует10_000 линии, ну твойfindFirst придется ждатьвсе 10_000 для расчета, даже если вы заботитесь только об одном.

РЕДАКТИРОВАТЬ

Это исправлено в Java 10, где мы возвращаем нашу лень: смотритеJDK-8075939

Ваш ответ на вопрос