Comment annuler un prédicat de référence de méthode

Dans Java 8, vous pouvez utiliser une référence de méthode pour filtrer un stream, par exemple:

Stream s = ...; long emptySsortingngs = s.filter(Ssortingng::isEmpty).count(); 

Y a-t-il un moyen de créer une référence de méthode qui est la négation d’une référence existante, c’est-à-dire quelque chose comme:

 long nonEmptySsortingngs = s.filter(not(Ssortingng::isEmpty)).count(); 

Je pourrais créer la méthode not comme ci-dessous mais je me demandais si le JDK offrait quelque chose de similaire.

 static  Predicate not(Predicate p) { return o -> !p.test(o); } 

    java-11 propose une nouvelle méthode Predicate # not

    Vous pouvez donc annuler la référence de la méthode:

     Stream s = ...; long nonEmptySsortingngs = s.filter(Predicate.not(Ssortingng::isEmpty)).count(); 

    Je prévois d’importer statiquement les éléments suivants pour permettre l’utilisation de la référence de méthode en ligne:

     public static  Predicate not(Predicate t) { return t.negate(); } 

    par exemple

     Stream s = ...; long nonEmptySsortingngs = s.filter(not(Ssortingng::isEmpty)).count(); 

    Mise à jour : – Le JDK / 11 pourrait également offrir une solution similaire .

    Il existe un moyen de composer une référence de méthode opposée à une référence de méthode actuelle. Voir la réponse de @vlasec ci-dessous qui montre comment, en convertissant explicitement la référence de méthode à un Predicate , puis en la convertissant en utilisant la fonction negate . C’est un moyen parmi d’autres, pas trop gênants, de le faire.

    Le contraire de ceci:

     Stream s = ...; int emptySsortingngs = s.filter(Ssortingng::isEmpty).count(); 

    est-ce:

     Stream s = ...; int notEmptySsortingngs = s.filter(((Predicate) Ssortingng::isEmpty).negate()).count() 

    ou ca:

     Stream s = ...; int notEmptySsortingngs = s.filter( it -> !it.isEmpty() ).count(); 

    Personnellement, je préfère la dernière technique car je trouve plus clair de la lire it -> !it.isEmpty() qu’une longue dissortingbution explicite verbeuse et de la neutraliser.

    On pourrait aussi faire un prédicat et le réutiliser:

     Predicate notEmpty = (Ssortingng it) -> !it.isEmpty(); Stream s = ...; int notEmptySsortingngs = s.filter(notEmpty).count(); 

    Ou, si vous disposez d’une collection ou d’un tableau, utilisez simplement une boucle for qui est simple, a moins de surcharge et * pourrait être ** plus rapide:

     int notEmpty = 0; for(Ssortingng s : list) if(!s.isEmpty()) notEmpty++; 

    * Si vous voulez savoir ce qui est plus rapide, utilisez JMH http://openjdk.java.net/projects/code-tools/jmh , et évitez le code de test manuel, à moins d’éviter toutes les optimisations JVM – voir Java 8: performances des stream vs collections

    ** Je suis en train de faire une erreur pour avoir suggéré que la technique en boucle est plus rapide. Il élimine la création d’un stream, élimine l’utilisation d’un autre appel de méthode (fonction négative pour le prédicat) et élimine une liste / un compteur d’accumulateur temporaire. Donc, quelques choses qui sont sauvées par la dernière construction peuvent le rendre plus rapide.

    Je pense que c’est plus simple et plus agréable, même si ce n’est pas plus rapide. Si le travail exige un marteau et un clou, n’apportez pas de scie à chaîne et de colle! Je sais que certains d’entre vous contestent cela.

    liste de souhaits: j’aimerais que les fonctions de Java Stream évoluent un peu maintenant que les utilisateurs de Java les connaissent mieux. Par exemple, la méthode “count” dans Stream peut accepter un Predicate afin que cela puisse être fait directement comme ceci:

     Stream s = ...; int notEmptySsortingngs = s.count(it -> !it.isEmpty()); or List list = ...; int notEmptySsortingngs = lists.count(it -> !it.isEmpty()); 

    Predicate ont des méthodes and or negate .

    Cependant, Ssortingng::isEmpty n’est pas un Predicate , c’est juste un Ssortingng -> Boolean lambda et il peut toujours devenir quelque chose, par exemple Function . L’inférence de type est ce qui doit se passer en premier. La méthode de filter déduit le type implicitement . Mais si vous le niez avant de le passer en argument, cela ne se produit plus. Comme @axtavt l’a mentionné, l’ inférence explicite peut être utilisée comme une méthode laide:

      s.filter(((Predicate) Ssortingng::isEmpty).negate()).count() 

    Il y a d’autres manières conseillées dans d’autres réponses, avec statique not méthode et lambda étant probablement les meilleures idées. Ceci conclut la section tl; dr .


    Cependant, si vous voulez une compréhension plus approfondie de l’inférence de type lambda, j’aimerais vous expliquer un peu plus en profondeur, en utilisant des exemples. Regardez-les et essayez de comprendre ce qui se passe:

      Object obj1 = Ssortingng::isEmpty; Predicate p1 = s -> s.isEmpty(); Function f1 = Ssortingng::isEmpty; Object obj2 = p1; Function f2 = (Function) obj2; Function f3 = p1::test; Predicate p2 = s -> s.isEmpty(); Predicate p3 = Ssortingng::isEmpty; 
    • obj1 ne comstack pas – lambdas doit déduire une interface fonctionnelle (= avec une méthode abstraite)
    • p1 et f1 fonctionnent bien, chacun induisant un type différent
    • obj2 lance un Predicate à l’ Object – idiot mais valide
    • f2 échoue à l’exécution – vous ne pouvez pas Predicate en Function , il ne s’agit plus d’inférence
    • f3 fonctionne – vous appelez le test méthode du prédicat défini par son lambda
    • p2 ne comstack pas – Integer n’a pas de méthode isEmpty
    • p3 ne comstack pas non plus – il n’y a pas de méthode statique Ssortingng::isEmpty avec l’argument Integer

    J’espère que cela aide à mieux comprendre le fonctionnement de l’inferrence de type.

    S’appuyant sur les réponses des autres et son expérience personnelle:

     Predicate blank = Ssortingng::isEmpty; content.stream() .filter(blank.negate()) 

    Une autre option consiste à utiliser la conversion en lambda dans des contextes non ambigus en une seule classe:

     public static class Lambdas { public static  Predicate as(Predicate predicate){ return predicate; } public static  Consumer as(Consumer consumer){ return consumer; } public static  Supplier as(Supplier supplier){ return supplier; } public static  Function as(Function function){ return function; } } 

    … puis importation statique de la classe utilitaire:

     stream.filter(as(Ssortingng::isEmpty).negate()) 

    Est-ce que Predicate#negate ne devrait pas être ce que vous cherchez?

    Dans ce cas, vous pouvez utiliser org.apache.commons.lang3.SsortingngUtils et faire

     int nonEmptySsortingngs = s.filter(SsortingngUtils::isNotEmpty).count(); 

    Vous pouvez utiliser les prédicats des collections Eclipse

     MutableList ssortingngs = Lists.mutable.empty(); int nonEmptySsortingngs = ssortingngs.count(Predicates.not(Ssortingng::isEmpty)); 

    Si vous ne pouvez pas modifier les chaînes de la List :

     List ssortingngs = new ArrayList<>(); int nonEmptyStrings = ListAdapter.adapt(strings).count(Predicates.not(String::isEmpty)); 

    Si vous n’avez besoin que d’une négation de Ssortingng.isEmpty() vous pouvez également utiliser SsortingngPredicates.notEmpty() .

    Note: Je consortingbue aux collections Eclipse.

    J’ai écrit une classe d’utilitaire complète (inspirée de la proposition d’Askar) qui peut prendre l’expression lambda de Java 8 et la transformer (le cas échéant) en n’importe quel lambda Java 8 standard défini dans le package java.util.function . Vous pouvez par exemple faire:

    • asPredicate(Ssortingng::isEmpty).negate()
    • asBiPredicate(Ssortingng::equals).negate()

    Comme il y aurait de nombreuses ambiguïtés si toutes les méthodes statiques étaient nommées as() , j’ai opté pour appeler la méthode “as” suivie du type renvoyé. Cela nous donne le plein contrôle de l’interprétation lambda. Vous trouverez ci-dessous la première partie de la classe utilitaire (quelque peu importante) révélant le motif utilisé.

    Jetez un oeil à la classe complète ici (à l’essentiel).

     public class FunctionCastUtil { public static  BiConsumer asBiConsumer(BiConsumer biConsumer) { return biConsumer; } public static  BiFunction asBiFunction(BiFunction biFunction) { return biFunction; } public static  BinaryOperator asBinaryOperator(BinaryOperator binaryOperator) { return binaryOperator; } ... and so on... }