Je sais que cela peut être une question très basique sur SO mais je veux savoir quelle est la différence entre une Predicate
et une Function
Interface en Java8?
Predicate<String> predicateTest = (s)-> s.length() > 5;
System.out.println(predicateTest.test("Predicate"));
Function<String, Boolean> functionTest = str -> str.length()> 5;
System.out.println(functionTest.apply("Function"));
Ici, dans mon exemple, les deux renvoient true
. La seule chose est que la façon d'appeler est différente?
Predicate<T>
Et Function<T, R>
Tout d'abord, un Predicate<T>
Est strictement une fonction booléenne:
_ _ _ _ _ _ _
| |
T --> | predicate | --> boolean
|_ _ _ _ _ _ _|
Alors que ce n'est pas nécessairement vrai pour un Function<T, R>
:
_ _ _ _ _ _ _
| |
T --> | function | --> R
|_ _ _ _ _ _ _|
Ce dernier consomme tout type d'objet comme le permet Predicate<T>
Mais peut varier dans le type de retour.
Predicate<T>
Et Function<T, R>
Le cas d'utilisation de Predicate<T>
Est lorsque vous avez besoin d'une fonction qui consomme un argument de type T
et renvoie un booléen. par exemple. qui peut être dans une situation où vous souhaitez filtrer un flux d'éléments, trouver le premier élément d'un flux qui remplit une condition en tant que telle de .filter(predicate).findFirst()
, ou vérifier la présence d'un élément d'un flux qui satisfait une certaine condition en tant que telle de anyMatch
, noneMatch
, allMatch
etc.
Le cas d'utilisation de Function<T, R>
Est lorsque vous avez besoin d'une fonction qui consomme un argument de type T
et le transforme en type R
par exemple cela peut être lors de l'appel de stream.map(func)
.
En ce qui concerne l'exemple d'extrait dans votre message Predicate<String>
Et Function<String, Boolean>
Sont la même chose en termes de ce qu'ils représentent, c'est-à-dire qu'ils représentent tous les deux une fonction prenant un String
et retournant un boolean
. Cependant, le premier évite de mettre la valeur renvoyée de boolean
à Boolean
alors que le second ne le fait pas.
Cela dit, cela ne signifie pas nécessairement où vous pouvez utiliser un Predicate<String>
, Vous pouvez également utiliser un Function<String, Boolean>
Ou vice versa.
Exemple:
Pendant que cela compile:
Predicate<String> predicate = p -> p.length() == 21;
Stream<String> stream = stringList().stream().filter(predicate);
Cela ne signifie pas:
Function<String, Boolean> function = p -> p.length() == 21;
Stream<String> stream = stringList().stream().filter(function);
et vice versa:
Pendant que cela fonctionne:
Function<String, Boolean> function = p -> p.length() == 21;
Stream<Boolean> stream = stringList().stream().map(function);
Cela ne signifie pas:
Predicate<String> predicate = p -> p.length() == 21;
Stream<Boolean> stream = stringList().stream().map(predicate);
dans ce cas, il n'y a pas de différence, cela ne concerne que les choses auxquelles vous pouvez postuler. Ainsi, par exemple, allMatch
attend un Predicate
, vous ne pouvez pas passer un Function
, même si logiquement ils font la même chose.
La réponse d'Aominè couvre les différences fondamentales. Je voudrais ajouter que les deux interfaces ont également différentes méthodes par défaut spécialisées, c'est-à-dire des méthodes que vous pouvez appeler sur n'importe quelle classe d'implémentation:
Predicate<T>
Predicate<T> and(Predicate<? super T> other)
- Renvoie un prédicat composé qui représente un ET logique de court-circuitage de ce prédicat et d'un autre.Predicate<T> or(Predicate<? super T> other)
- Renvoie un prédicat composé qui représente une logique de court-circuit OR de ce prédicat et d'un autre.negate()
- Renvoie un prédicat qui représente la négation logique de ce prédicat.Function<T,R>
<V> Function<T,V> andThen(Function<? super R,? extends V> after)
- Renvoie une fonction composée qui applique d'abord cette fonction à son entrée, puis applique la fonction after
au résultat.<V> Function<V,R> compose(Function<? super V,? extends T> before)
- Renvoie une fonction composée qui applique d'abord la fonction before
à son entrée, puis applique cette fonction au résultat.Comme vous pouvez le voir, Predicate
a des méthodes utiles pour créer des conditions complexes, tout comme les opérateurs que vous utiliseriez dans une instruction if
régulière, tandis que Function
a des méthodes qui prennent en charge le chaînage simple .
Un Predicate
ne peut renvoyer qu'un boolean
(résultat de test()
) tandis que Function
fait une transformation et peut retourner n'importe quoi (résultat de apply()
).
Un Predicate
est utilisé pour tester une condition.
Un Function
est utilisé pour effectuer une transformation.
En théorie, il ne devrait pas y avoir de différence fonctionnelle entre Predicate<T>
et Function<T, Boolean>
. Un Predicate
est juste une fonction qui prend un objet d'un certain type et retourne un booléen. Un Function
est une généralisation qui peut renvoyer n'importe quel type, pas seulement les Boolean
.
Il peut y avoir des détails d'implémentation dans Java lui-même qui les rendent distincts, mais ils devraient être les mêmes en théorie.
Un exemple serait si une interface ne pouvait accepter qu'un Predicate<String>
, pas un Function<String, Boolean
.
D'un point de vue technique, un Predicate<T>
est juste une fonction qui prend un T
et renvoie un résultat primitif booléen. Cependant, du point de vue de l'utilisation, un Predicate<T>
est un concept totalement différent d'un Function<T, Boolean>
.
Nous utilisons un Predicate<T>
pour effectuer une opération de filtrage, dans un pipeline de flux par exemple, on prend un Stream<T>
de taille n
, filtrez-le à l'aide d'un Predicate<T>
pour obtenir un flux de taille inférieure ou égale à n
. Pendant ce temps, un Function<T, Boolean>
dans un pipeline de flux est utilisé pour effectuer une opération de mappage pour transformer un Stream<T>
dans une Stream<Boolean>
.
Comme vous pouvez le voir, Predicate<T>
et un Function<T, Boolean>
sont techniquement les mêmes (en ignorant le wrapper Boolean
pour plus de simplicité), mais lorsqu'il est placé dans un contexte spécifique (pipelines de flux par exemple), c'est une histoire totalement différente car chacun d'eux joue un rôle distinct.