web-dev-qa-db-fra.com

Combinaison de prédicats lambda Java 8 avec des opérateurs logiques

J'ai un Stream<SomeClass> stream alors que SomeClass a des méthodes booléennes isFoo() et isBar().

Je voudrais vérifier que tous les éléments du flux ont à la fois isFoo() et isBar() égal à true. Je peux vérifier ces conditions individuellement via SomeClass:isFoo et SomeClass::isBar lambdas.

Mais comment pourrais-je combiner ces deux lambdas avec un opérateur logique tel que and/&&?

Un moyen évident consiste à écrire un lambda supplémentaire:

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

Mais j'aimerais éviter d'écrire un lambda supplémentaire.

Une autre méthode consiste à convertir en Predicate<? super SomeClass>:

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

Y a-t-il une meilleure façon - sans castes et lambdas explicites?

8
lexicore

S'il existait une méthode hypothétique Predicate.of, vous pourriez écrire:

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

Cela n'existe pas, mais vous pouvez l'écrire vous-même.

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

Cela dit, j'irais personnellement avec votre première option.

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

Les références aux méthodes :: sont agréables, mais vous devez parfois écrire des lambdas explicites.

12
John Kugelman

Cela pourrait ne pas être considéré comme la réponse (ne votez pas s'il vous plait s'il ne le fait pas), mais je en quelque sorte ai le même besoin de croquer quelques prédicats et j'ai juste écrit un petit utilitaire pour cela.

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

Vous devez absolument utiliser la méthode filter de Stream. Filtre sélectionne les éléments de la liste qui correspondent au prédicat donné. 

Cette ligne sélectionne les éléments qui sont simultanément Foo AND Bar:

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

La sortie est un flux, vous devriez donc rassembler les éléments dans une liste pour les utiliser:

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

Pour vérifier si tous les éléments du flux sont à la fois Foo et Bar, vous pouvez comparer la taille de la liste d'origine à la taille du flux filtré:

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