Java stream: use optional filter() operations on chaining

  • A+
Category:Languages

Note: this question is not related to java.util.Optional.

When dealing with streams, I often use logic like this:

 Stream<FooBar> stream = myInitialStream();  if (needsFilter1) stream = stream.filter(c -> whatever1());  if (needsFilter2) stream = stream.filter(c -> whatever2());  ...  return stream.collect(toList()); 

What I am trying to achieve is converting the code above to a single-expression using chaining. I find this more readable and straight forward. Until now, the only way I found to achieve that was:

return myInitialStream()        .filter(needsFilter1? c->whatever1() : c->true)        .filter(needsFilter2? c->whatever2() : c->true)        .collect(toList()); 

Still, this would make unnecessary calls to those trivial c->true lamdas, which might produce some performance cost when scaling up.

So my question is: is there a better way of producing chained stream expressions that include optional filtering?

UPDATE: Maybe I did not make it clear enough, but the point of my question is finding a single-expression solution. If I have to use multiple statements (to initialize a predicate, for example), I could also use the first code-block of my question which essentially does the same.

 


Chain the predicates according to the conditions using Predicate::and returning a new Predicate.

Predicate<FooBar> predicate = c -> whatever();  if (condition1) { predicate = predicate.and(c -> whatever1()); } if (condition2) { predicate = predicate.and(c -> whatever2()); }  List<FooBar> dest = list.stream()     .filter(predicate)     .collect(Collectors.toList()); 

Upon an update requesting a single expression. You a need source of mapped conditions to predicates anyway. With the data structure Map<Supplier<Boolean>, Predicate<Integer>>, where a key is a Supplier of a condition whether a value (Predicate<FooBar>) shall be used.

With reducing the entries of a map to a new Predicate<FooBar> using chaining these Predicates with Predicate::and, for which their Supplier<Boolean> returns true (the condition is valid).

Having a Map of the conditions:

Map<Supplier<Boolean>, Predicate<FooBar>> map = new HashMap<>(); map.put(() -> needsFilter1, c -> whatever1()); map.put(() -> needsFilter2, c -> whatever2()); ... 

Here is a single Stream statement:

List<Integer> dest = list         .stream()         .filter(map.entrySet()                            // filter with a predicate ...                 .stream()                 .filter(e -> e.getKey().get())            // .. where a condition is 'true'                 .map(Entry::getValue)                     // .. get Predicates                 .reduce(i -> true, (l, r) -> l.and(r)))   // .. reduce them using AND         .collect(Collectors.toList());                

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: