Reputation: 12316
it is possible, with Java 8 stream API, to create Stream that is not evaluated until is necessary?
I mean.
I have a stream that processes a list of elements, in one of the middle operations (map) I have to read go through another stream and I want to have that Stream in another variable to be used through all other first stream objects, but if there Are no objects to process I would like to avoid process second stream.
I think it's easier to check with code:
Message[] process(@Nullable Message[] messages) {
Stream<Function> transformationsToApply =
transformations
.stream()
.filter(transformation -> transformationIsEnabled(transformation.getLeft()))
.map(Pair::getRight);
return Arrays.stream(messages != null ? messages : new Message[0])
.filter(Objects::nonNull)
.map(agentMessage -> {
transformationsToApply.forEach(transformation -> processMessage(transformation, agentMessage));
return agentMessage;
})
.toArray(Message[]::new);
}
My doubt is about first one stream generation, I would like to return stream based on the list that I processed, but I only to want to do if it is gonna be used (And use same for all message elemets).
Any idea..?
Upvotes: 1
Views: 1418
Reputation: 3453
Streams are not stateful, so there's no easy way to have it do something only when the first element is processed. In this case, you could just check the messages
parameter and return early if there's nothing to do:
Message[] process(@Nullable Message[] messages) {
if (messages == null || messages.length == 0) return new Message[0];
List<Function> transformationsToApply = transformations.stream()
.filter(transformation -> transformationIsEnabled(transformation.getLeft()))
.map(Pair::getRight)
.collect(Collectors.toList());
return Arrays.stream(messages)
.filter(Objects::nonNull)
.map(agentMessage -> {
transformationsToApply.forEach(transformation -> processMessage(transformation, agentMessage));
return agentMessage;
})
.toArray(Message[]::new);
}
I also fixed the issue with reusing the transformationsToApply
stream, you need to make it a collection before you can iterate over it multiple times.
Upvotes: 1
Reputation: 18235
Don't worry, your transformationsToApply
is not evaluated until you attach a terminal operation.
Intermediate operations return a new stream. They are always lazy; executing an intermediate operation such as filter() does not actually perform any filtering, but instead creates a new stream that, when traversed, contains the elements of the initial stream that match the given predicate. Traversal of the pipeline source does not begin until the terminal operation of the pipeline is executed.
Upvotes: 2