Reputation: 13
As indicated in the title, I want to generate stream from list, but the list need a large performance cost, and the stream may not be really used.
Something I need is like this:
Stream<T> stream = Stream.fromList(() -> calculateList(...))
.filter(...)
.map(...)
// TODO
;
//#region some case why I want delayed stream instead of other way.
if (condition$1) {
// that is why I don't want to re-order those code.
stream.forEach(...);
return;
}
var something$1 = ...; // that should only execute after the condition$1 not passed.
if (condition$2) {
// that is why I don't want to use `Supplier<Stream<T>>`.
stream = stream.concat(Stream.fromList(() -> calculateOthList(...)));
}
var something$2 = ...;
if (condition$3) {
// that is why I dont want to use `Stream<Supplier<Stream<T>>>` (and what's more, it not easy to read).
stream = stream.filter(...).peek(...);
}
... // as you see, the most important thing of those code is to deal the stream, it's data-driven.
//#endregion
// TODO may be return if some condition not passed.
// TODO and even worse, some exception may be throw.
stream.forEach(...); // TODO really use the stream.
Is there any built-in methods to do that? or maybe any way to implement elegantly?
Upvotes: 0
Views: 512
Reputation: 23339
You can create a Spiliterator
from a Supplier
and get a Stream back which makes your Stream creation lazy. For example:
Supplier<Spliterator<Integer>> supplier = () -> calculateList(...).spliterator();
Stream<Integer> stream = StreamSupport.stream(supplier, Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED, false);
Upvotes: 2
Reputation: 40047
You could do it like this.
List<Integer> list = List.of(1,2,3,4,5,6);
Function<List<Integer>,Stream<Integer>> fnc = a->a.stream().filter(b->b%2 == 0).map(b->b*20);
fnc.apply(list).forEach(System.out::println);
In your case it could be
fnc.apply(calculateList(...)).forEach(....);
Upvotes: 0
Reputation: 5458
In this situation you really need to provide a Supplier
. The Supplier
will evaluate your list populating method when you want it. There are two ways to achieve this:
Supplier<T> streamSupplier = () -> calculateList(...).stream();
// other code
// then use it
streamSupplier.get().forEach(...);
Or maybe you really want a stream, so might do something like this:
Stream<Supplier<Stream<T>> streamOfStreamSuppliers = Stream.of(() -> calculateList().stream());
// other code
// then use it by unpacking the supplied stream
// and then flatmapping that
streamOfStreamSuppliers.map(Supplier::get)
.flatMap(Function.identity())
.forEach(...);
This has the side effect of allowing you to put multiple streams into the mix.
The bigger question, though, is why you don't reorganise your code so that your stream is created when it's first needed?
Upvotes: 0
Reputation: 9043
Probably the simplest thing is to replace your Stream
with a Supplier<Stream>
e.g.
Supplier<Stream<T>> stream = () -> Stream.fromList(() -> calculateList(...));
but if you can't do that, you can implement a lazy Stream like this:
Stream<T> lazyStream = Stream.<Supplier<List<T>>>of(() -> calculateList())
.map(Supplier::get)
.flatMap(List::stream);
Upvotes: 0