Combining Java 8 lambda predicates with logical operators

12,715

Solution 1

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.

Solution 2

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);
}

Solution 3

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());

Share:
12,715
lexicore
Author by

lexicore

Please see my Xing profile if you want a business contact.

Updated on July 28, 2022

Comments

  • lexicore
    lexicore over 1 year

    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?

  • lexicore
    lexicore almost 7 years
    I don't need to select isFoo() and isBar() elements, I need to check if all elements of the stream are both isFoo() and isBar().
  • Andrea
    Andrea almost 7 years
    Then you could simply compare the size of the original list with the size of the filtered list, see my edit.
  • lexicore
    lexicore almost 7 years
    This looks really suboptimal.
  • yiwei
    yiwei over 6 years
    I think this is a good answer. OP is looking to not combine lambdas with &&, but it's trivial to wrap the lambdas in a Predicate<T> and then apply this answer.
  • whiskeysierra
    whiskeysierra over 5 years
    This will fail if predicates is empty.
  • Eugene
    Eugene over 5 years
    @whiskeysierra good point! I guess orElse would suffice here