<T> Stream.fromForEach(Consumer<Consumer<T>>)
Remi Forax
forax at univ-mlv.fr
Sat May 21 22:54:07 UTC 2022
Hi all,
a stream is kind of push iterator so it can be created from any object that has a method like forEach(Consumer),
but sadly there is no static method to create a Stream from a Consumer of Consumer so people usually miss that creating a Stream from events pushed to a consumer is easy.
By example, let say i've a very simple parser like this, it calls the listener/callback for each tokens
record Parser(String text) {
void parse(Consumer<? super String> listener) {
for(var token: text.split(" ")) {
listener.accept(token);
}
}
}
Using the method Stream.fromForEach, we can create a Stream from the sequence of tokens that are pushed through the listener
var parser = new Parser("1 2");
var stream = Stream.fromForEach(parser::parse);
It can also works with an iterable, an optional or even a collection
Iterable<String> iterable = ...
var stream = Stream.fromForEach(iterable::forEachRemaning);
Optional<String> optional = ...
var stream = Stream.fromForEach(optional::ifPresent);
List<String> list = ...
var stream = Stream.fromForEach(list::forEach);
I known the last two examples already have their own method stream(), it's just to explain how Stream.fromForEach is supposed to work.
In term of implementation, Stream.fromForEach() is equivalent to creating a stream using a mapMulti(), so it can be implemented like this
static <T> Stream<T> fromForEach(Consumer<? super Consumer<T>> forEach) {
return Stream.of((T) null).mapMulti((__, consumer) -> forEach.accept(consumer));
}
but i think that Stream.fromForEach(iterable::forEachRemaning) is more readable than Stream.of(iterable).mapMult(Iterable::forEachRemaining).
The name fromForEach is not great and i'm sure someone will come with a better one.
regards,
Rémi
More information about the core-libs-dev
mailing list