Let us have a stream of objects, resulting from a sequence of operations (e.g. mapping, filtering, flatmapping, etc.). Now I want to do a certain operation on them, but only if a given predicate is true. Otherwise I want to immediately return something else.
A simple example. I have a stream of different food objects. If all of them are edible I want to perform a cook operation on them and return the list of cooked food. But if any of them turns out to not be edible I want to immediately return an empty list.
Few solutions come to my mind, but I am not satisfied with any of them.
I could first perform an allMatch
operation with isEdible
predicate on the stream, but it will result in terminating it and I would need to repeat preliminary operations once more.
I could persist the collection that is the result of preliminary operations before checking the edibility, but therefore I need to perform them for all elements. Which is suboptimal, because it may turn out, that the first of them is not edible and allMatch
would return much, much earlier.
Or I could design a hacky reduce
routine, but it would also be unable to stop processing elements when predicate fails.
What I hope for is something like the code below. Is it possible with current API?
source.stream()
// some operations
.ifAny(food -> !food.isEdible(), new LinkedList<Food>())
// other operations if previous step not failed
.peek(food -> food.prepare())
.collect(Collectors.toList());
Not exactly what you wanted, but using the ternary operator will make your two step solution look cleaner, it also should have optimal performance:
return source.stream()
.allMatch(this::isEdible)
? source.stream()
.map(this::prepare()) // do stuff
.collect(Collectors.toList())
: Collections.emptyList();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With