Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8151408

add a stream factory method that can produce a finite stream

XMLWordPrintable

    • Icon: Enhancement Enhancement
    • Resolution: Unresolved
    • Icon: P5 P5
    • None
    • None
    • core-libs

      The stream factories that produce streams given some functions, such as Stream.generate() and the 2-arg Stream.iterate(), produce infinite streams. The 3-arg Stream.iterate() introduced by JDK-8072727 is helpful, but it terminates the stream based on a predicate over one of the generated values. There are cases where only the stream source itself knows whether the stream has ended; it might not even be able to produce a value that can be tested with a predicate.

      Thus, an unfulfilled need is to have a stream factory method that produces stream elements but which can also signal the end of the stream. The only way to do this currently is to write a custom spliterator. It would be much more convenient if it were possible to produce stream elements with a single lambda expression, as creating a spliterator unavoidably requires a fair amount of boilerplate.

      The simplest approach is to use a skeleton AbstractSpliterator and allow a lambda expression to provide the implementation of tryAdvance(). The resulting API would look something like this on Stream:

          public static <T> Stream<T> produce(Predicate<Consumer<T>> advancer)

      The Predicate<Consumer<T>> is somewhat odd but it has the same shape as Spliterator.tryAdvance(). It also has the same requirements: to call the consumer with a single element and return true, or to return false. End-of-stream is signaled when the advancer returns false.

      Another variant would be to have end-of-stream signaled using an Optional:

          public static <T> Stream<T> produce(Supplier<Optional<T>> supplier)

      This might be more convenient, if we can convince ourselves that the boxing overhead of Optional is reasonable, or if it can be optimized away in a sufficient number of cases.

      There are a bunch of other variants are possible.

      Here's an example use case that uses

          Scanner sc = new Scanner("1 2 3 4 foo");
          IntStream.produce(() -> sc.hasNextInt()
                                             ? OptionalInt.of(sc.nextInt())
                                              : OptionalInt.empty())
              .forEach(System.out::println);

          assert sc.hasNext();
          System.out.println(sc.next()); // prints "foo"

      This example prints "1 2 3 4" (on separate lines) and then leaves the Scanner in a known state so that it can be used reliably by subsequent code.

            smarks Stuart Marks
            smarks Stuart Marks
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated: