How can I apply a collection of predicates to a Java stream?
The following code shall illustrate what I have in mind:
final Collection<Predicate<MyObject>> filters = getFilters();
final Stream<MyObject> oStream = getMyObjectStream();
oStream
.filterAll(filters) // <- this one doesn't exist
.forEach(System.out::println);
I'm currently using a function .filter(m -> applyAllFilters(m, filters))
with a classic loop, but wonder if there is a more "streamy" way?
boolean applyAllFilters(final MyObject m, final Collection<Predicate<MyObject>> filters) {
Iterator Predicate<MyObject> iter = filters.iterator();
while(iter.hasNext()) {
Predicate<MyObject> p = iter.next();
if (!p.test(m)) {
return false;
}
}
return true;
}
You can simply reduce all the predicates into one single Predicate that is anded with all of them like this:
oStream
.filter(filters.stream().reduce(Predicate::and).orElseThrow())
.forEach(System.out::println);
Alternatively, if you expect the list of filters to be empty in some cases, you could do it this way:
oStream
.filter(filters.stream().reduce(o -> true, Predicate::and))
.forEach(System.out::println);
You can pre-create a filter that meet all the criteria.
Suppose you have three Predicate <MyObject> a, b, c
. These can be combined as follows regardless of oStream
.
Predicate<MyObject> allFilter = e -> a.test(e) && b.test(e) && c.test(e);
So you can do like this.
Predicate<MyObject> filterAll = filters.stream()
.reduce(Predicate::and).orElse(e -> true);
oStream
.filter(filterAll)
.forEach(System.out::println);
You can use a loop to apply the filters:
final Collection<Predicate<MyObject>> filters = getFilters();
Stream<MyObject> oStream = getMyObjectStream();
for(Predicate<MyObject> p : filters) {
oStream = oStream.filter(p);
}
oStream.forEach(System.out::println);