How to apply multiple predicates to a java.util.Stream?

java, java-8, java-stream, lambda, predicate

Solution

I am assuming your `Filter` is a type distinct from `java.util.function.Predicate`, which means it needs to be adapted to it. One approach which will work goes like this:

things.stream().filter(t -> filtersCollection.stream().anyMatch(f -> f.test(t)));

This incurs a slight performance hit of recreating the filter stream for each predicate evaluation. To avoid that you could wrap each filter into a `Predicate` and compose them:

things.stream().filter(filtersCollection.stream().<Predicate>map(f -> f::test)
                       .reduce(Predicate::or).orElse(t->false));

However, since now each filter is behind its own `Predicate`, introducing one more level of indirection, it is not clear-cut which approach would have better overall performance.

Without the adapting concern (if your `Filter` happens to be a `Predicate`) the problem statement becomes much simpler and the second approach clearly wins out:

things.stream().filter(
   filtersCollection.stream().reduce(Predicate::or).orElse(t->true)
);

Problem

How can I apply multiple predicates to a `java.util.Stream's` `filter()` method? This is what I do now, but I don't really like it. I have a `Collection` of things, and I need to reduce the number of things based on the `Collection` of filters (predicates): ``` Collection<Thing> things = someGenerator.someMethod(); List<Thing> filtered = things.parallelStream().filter(p -> { for (Filter f : filtersCollection) { if (f.test(p)) return true; } return false; }).collect(Collectors.toList()); ``` I know that if I knew number of filters up-front, I could do something like this: ``` List<Thing> filtered = things.parallelStream().filter(filter1).or(filter2).or(filter3)).collect(Collectors.toList()); ``` But how can I apply an unknown number of predicates without mixing programming styles? For now, it looks sort of ugly...

Original source

Related problems