Dans Java 8, vous pouvez utiliser une référence de méthode pour filtrer un flux, par exemple:
Stream<String> s = ...;
long emptyStrings = s.filter(String::isEmpty).count();
Existe-t-il un moyen de créer une référence de méthode qui soit la négation d'une référence existante, c'est-à-dire quelque chose comme:
long nonEmptyStrings = s.filter(not(String::isEmpty)).count();
Je pouvais créer la not
méthode comme ci-dessous mais je me demandais si le JDK offrait quelque chose de similaire.
static <T> Predicate<T> not(Predicate<T> p) { return o -> !p.test(o); }
Predicate.not(Predicate)
méthode statique . Mais ce problème est toujours ouvert, nous le verrons au plus tôt dans Java 12 (si jamais).Réponses:
Predicate.not( … )
java-11propose une nouvelle méthode Predicate # not
Vous pouvez donc annuler la référence de la méthode:
la source
Je prévois d'importer de manière statique les éléments suivants pour permettre à la référence de méthode d'être utilisée en ligne:
par exemple
Mise à jour : à partir de Java-11, le JDK propose également une solution similaire intégrée .
la source
Il existe un moyen de composer une référence de méthode qui est l'opposé d'une référence de méthode actuelle. Voir la réponse de @ vlasec ci-dessous qui montre comment en exprimant explicitement la référence de méthode en a
Predicate
puis en la convertissant à l'aide de lanegate
fonction. C'est une façon parmi quelques autres façons pas trop gênantes de le faire.Le contraire:
est-ce:
ou ca:
Personnellement, je préfère la technique ultérieure parce que je trouve plus clair à lire
it -> !it.isEmpty()
qu'un long casting explicite verbeux et ensuite à nier.On pourrait aussi faire un prédicat et le réutiliser:
Ou, si vous avez une collection ou un tableau, utilisez simplement une boucle for qui est simple, a moins de surcharge et * pourrait être ** plus rapide:
* Si vous voulez savoir ce qui est plus rapide, utilisez JMH http://openjdk.java.net/projects/code-tools/jmh et évitez le code de référence manuel à moins qu'il n'évite toutes les optimisations JVM - voir Java 8: performances des flux vs Collections
** Je reçois un flak pour avoir suggéré que la technique for-loop est plus rapide. Il élimine la création d'un flux, il élimine l'utilisation d'un autre appel de méthode (fonction négative pour le prédicat) et il élimine une liste / compteur d'accumulateurs temporaires. Donc, quelques choses qui sont enregistrées par la dernière construction qui pourraient 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 nécessite un marteau et un clou, n'apportez pas de tronçonneuse et de colle! Je sais que certains d'entre vous s'y opposent.
wish-list: j'aimerais voir les
Stream
fonctions Java évoluer un peu maintenant que les utilisateurs Java les connaissent mieux. Par exemple, la méthode 'count' dans Stream pourrait accepter unPredicate
afin que cela puisse être fait directement comme ceci:la source
Predicate.negate(String::isEmpty);
sans le casting encombrant.Predicate
a des méthodesand
,or
etnegate
.Cependant, ce
String::isEmpty
n'est pas unPredicate
, c'est juste unString -> Boolean
lambda et il pourrait encore devenir n'importe quoi, par exempleFunction<String, Boolean>
. L'inférence de type est ce qui doit se produire en premier. Lafilter
méthode déduit implicitement le type . 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:Il existe d'autres moyens conseillés dans d'autres réponses, avec
not
méthode et lambda étant probablement les meilleures idées. Ceci conclut la section tl; dr .Cependant, si vous souhaitez une compréhension plus approfondie de l'inférence de type lambda, je voudrais l'expliquer un peu plus en profondeur, à l'aide d'exemples. Regardez-les et essayez de comprendre ce qui se passe:
Predicate
àObject
- idiot mais validePredicate
de conversion versFunction
, il ne s'agit plus d'inférencetest
qui est définie par son lambdaInteger
n'a pasisEmpty
méthodeString::isEmpty
méthode statique avecInteger
argumentJ'espère que cela vous aidera à mieux comprendre comment fonctionne l'inférence de type.
la source
S'appuyant sur les réponses et l'expérience personnelle des autres:
la source
::
référence fonctionnelle comme on pourrait le souhaiter (String::isEmpty.negate()
), mais si vous attribuez d'abord à une variable (ou transtypez enPredicate<String>
premier), cela fonctionne. Je pense que lambda w /!
sera le plus lisible dans la plupart des cas, mais il est utile de savoir ce qui peut et ne peut pas être compilé.Une autre option consiste à utiliser la conversion lambda dans des contextes non ambigus en une seule classe:
... puis importez statiquement la classe d'utilité:
la source
Ça ne devrait pas
Predicate#negate
être ce que vous cherchez?la source
Predicate
première.String::isEmpty()
àPredicate<String>
avant - il est très laid.Predicate<String> p = (Predicate<String>) String::isEmpty;
etp.negate()
.s -> !s.isEmpty()
dans ce cas!Dans ce cas , u pourrait utiliser
org.apache.commons.lang3.StringUtils
et fairela source
String::isEmpty
comme exemple. Ce sont toujours des informations pertinentes si vous avez ce cas d'utilisation, mais s'il ne répond qu'au cas d'utilisation de String, il ne doit pas être accepté.J'ai écrit une classe utilitaire complète (inspirée de la proposition d'Askar) qui peut prendre l'expression lambda Java 8 et les transformer (le cas échéant) en n'importe quel lambda Java 8 standard défini défini dans le package
java.util.function
. Vous pouvez par exemple faire:asPredicate(String::isEmpty).negate()
asBiPredicate(String::equals).negate()
Parce qu'il y aurait de nombreuses ambiguïtés si toutes les méthodes statiques étaient nommées juste
as()
, j'ai choisi d'appeler la méthode "as" suivie du type retourné. Cela nous donne un contrôle total sur l'interprétation lambda. Ci-dessous se trouve la première partie de la classe d'utilité (assez large) révélant le modèle utilisé.Jetez un oeil à la classe complète ici (à l'essentiel).
la source
Vous pouvez utiliser les prédicats des collections Eclipse
Si vous ne pouvez pas modifier les chaînes de
List
:Si vous avez seulement besoin d'une négation,
String.isEmpty()
vous pouvez également utiliserStringPredicates.notEmpty()
.Remarque: je suis un contributeur aux collections Eclipse.
la source
Vous pouvez accomplir cela aussi longtemps
emptyStrings = s.filter(s->!s.isEmpty()).count();
la source
Si vous utilisez Spring Boot (2.0.0+), vous pouvez utiliser:
Qui fait:
return (str != null && !str.isEmpty());
Il aura donc l'effet de négation requis pour
isEmpty
la source