-
Enhancement
-
Resolution: Unresolved
-
P5
-
None
-
None
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.
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.
- relates to
-
JDK-8318856 java.util.stream.Stream should close closeable spliterator
-
- New
-