Reputation: 43651
I have a Stream<SomeClass> stream
whereas SomeClass
has boolean methods isFoo()
and isBar()
.
I'd like to check that all elements in the stream have both isFoo()
and isBar()
equals to true
. I can check this conditions individually via SomeClass:isFoo
and SomeClass::isBar
lambdas.
But how would I 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'd like to avoid writing an extra lambda.
Another way is to cast to Predicate<? super SomeClass>
:
stream.allMatch(((Predicate<? super SomeClass>) SomeClass::isFoo).and(SomeClass::isBar));
Is there a better way - without casts and explicit lambdas?
Upvotes: 9
Views: 17156
Reputation: 120848
This might not qualify as the answer (please don't up vote it if it does not), but I sort of had the same need, to munch together some predicates and I just wrote a small utility for that.
private static <T> Predicate<T> andPredicates(Predicate<T>... predicates) {
return Arrays.stream(predicates).reduce(Predicate::and).orElse(x -> true);
}
Upvotes: 12
Reputation: 2556
You could filter and only collect the size of the list and compare with the original list :
long count = list.stream().filter(SomeClass::isFoo).filter(SomeClass::isBar).collect(Collectors.counting());
Upvotes: 1
Reputation: 795
You should definitely use the filter method of Stream. Filter select the elements of the list that match the given predicate.
This line select the elements which are Foo AND Bar at the same time:
list.stream().filter(SomeClass::isFoo).filter(SomeClass::isBar)
The output is a Stream, so you should collect the elements in a List to actually use them:
list.stream().filter(SomeClass::isFoo).filter(SomeClass::isBar).collect(Collectors.toList());
In order to check if all the elements of the stream are both Foo and Bar, you could compare the size of the original 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();
}
Upvotes: 0
Reputation: 361537
If there were a hypothetical Predicate.of
method, you could write:
stream.allMatch(Predicate.of(SomeClass::isFoo).or(SomeClass::isBar));
It doesn't exist, but you could write it yourself.
public final class Predicates {
public static <T> Predicate<T> of(Predicate<T> predicate) {
return predicate;
}
}
That said, I would personally go with your first option.
stream.allMatch(item -> item.isFoo() && item.isBar());
::
method references are nice but sometimes you have to write explicit lambdas.
Upvotes: 13