Combining Java 8 lambda predicates with logical operators

I have a Stream<SomeClass> stream , while SomeClass has the boolean methods isFoo() and isBar() .

I want to check that all elements in the stream have both isFoo() and isBar() equal to true . I can check these conditions individually with SomeClass:isFoo and SomeClass::isBar lambdas.

But how would you combine these two lambdas with a logical operator like and / && ?

One obvious way is to write an extra lambda:

 stream.allMatch(item -> item.isFoo() && item.isBar()); 

But I would like not to write extra lambda.

Another way is to pass Predicate<? super SomeClass> Predicate<? super SomeClass> :

 stream.allMatch(((Predicate<? super SomeClass>) SomeClass::isFoo).and(SomeClass::isBar)); 

Is there a better way - without throws and explicit iambds?

+5
source share
4 answers

If there was a hypothetical Predicate.of method, you could write:

 stream.allMatch(Predicate.of(SomeClass::isFoo).or(SomeClass::isBar)); 

It does not exist, but you can write it yourself.

 public final class Predicates { public static <T> Predicate<T> of(Predicate<T> predicate) { return predicate; } } 

However, I personally would go with your first option.

 stream.allMatch(item -> item.isFoo() && item.isBar()); 

:: method references are good, but sometimes you have to write explicit shortcuts.

+10
source

This may not qualify as an answer (please do not vote if it is not), but I had the same need to combine some predicates, and I just wrote a small utility for this.

 private static <T> Predicate<T> andPredicates(Predicate<T>... predicates) { return Arrays.stream(predicates).reduce(Predicate::and).orElse(x -> true); } 
+5
source

You should definitely use the filter method for the stream. The filter selects the list items that match the given predicate.

This line selects elements that are Foo AND Bar at the same time:

 list.stream().filter(SomeClass::isFoo).filter(SomeClass::isBar) 

The output is a stream, so you have to collect the elements in a list in order to actually use them:

  list.stream().filter(SomeClass::isFoo).filter(SomeClass::isBar).collect(Collectors.toList()); 

To check if all stream elements are both Foo and Bar, you can compare the size of the source list with the size of the filtered stream:

 public static Boolean isFooBar(List<SomeClass> list) { return list.size() == list.stream().filter(SomeClass::isFoo).filter(SomeClass::isBar).count(); } 
0
source

You can filter and collect only the size of the list and compare it with the original list:

long count = list.stream().filter(SomeClass::isFoo).filter(SomeClass::isBar).collect(Collectors.counting());

0
source

Source: https://habr.com/ru/post/1262583/


All Articles