Sometimes you want to filter a Stream
with more than one condition:
myList.stream().filter(x -> x.size() > 10).filter(x -> x.isCool()) ...
or you could do the same with a complex condition and a single filter
:
myList.stream().filter(x -> x.size() > 10 && x -> x.isCool()) ...
My guess is that the second approach has better performance characteristics, but I don't know it.
The first approach wins in readability, but what is better for the performance?
The code that has to be executed for both alternatives is so similar that you can’t predict a result reliably. The underlying object structure might differ but that’s no challenge to the hotspot optimizer. So it depends on other surrounding conditions which will yield to a faster execution, if there is any difference.
Combining two filter instances creates more objects and hence more delegating code but this can change if you use method references rather than lambda expressions, e.g. replace filter(x -> x.isCool())
by filter(ItemType::isCool)
. That way you have eliminated the synthetic delegating method created for your lambda expression. So combining two filters using two method references might create the same or lesser delegation code than a single filter
invocation using a lambda expression with &&
.
But, as said, this kind of overhead will be eliminated by the HotSpot optimizer and is negligible.
In theory, two filters could be easier parallelized than a single filter but that’s only relevant for rather computational intense tasks¹.
So there is no simple answer.
The bottom line is, don’t think about such performance differences below the odor detection threshold. Use what is more readable.
¹…and would require an implementation doing parallel processing of subsequent stages, a road currently not taken by the standard Stream implementation