J'ai vu dans certains projets que les gens utilisent Predicate
s au lieu de simples instructions if, comme illustré par un exemple simple ci-dessous:
int i = 5;
// Option 1
if (i == 5) {
// Do something
System.out.println("if statement");
}
// Option 2
Predicate<Integer> predicate = integer -> integer == 5;
if (predicate.test(i)) {
// Do something
System.out.println("predicate");
}
Quel est l'intérêt de préférer Predicate
s aux instructions if?
Pour l'exemple exact que vous avez fourni, l'utilisation d'un prédicat est un gros sur-kill. Le compilateur puis le runtime créeront:
- une méthode (prédicat désucréé)
- une .class qui implémentera Java.util.Predicate
- une instance de la classe créée à 2
tout cela par rapport à une simple instruction if.
Et tout cela pour un prédicat sans état . Si votre prédicat est plein d'état, comme:
Predicate<Integer> p = (Integer j) -> this.isJGood(j); // you are capturing "this"
puis chaque fois que vous utiliserez ce prédicat, une nouvelle instance sera créée (au moins sous la JVM actuelle).
La seule option viable de l'OMI pour créer un tel prédicat est, bien sûr, de le réutiliser à plusieurs endroits (comme passer comme arguments aux méthodes).
L'utilisation d'un prédicat rend votre code plus flexible.
Au lieu d'écrire une condition qui vérifie toujours si i == 5
, vous pouvez écrire une condition qui évalue un Predicate
, qui vous permet de passer différents Predicate
s implémentant différentes conditions.
Par exemple, le Predicate
peut être passé comme argument à une méthode:
public void someMethod (Predicate<Integer> predicate) {
if(predicate.test(i)) {
// do something
System.out.println("predicate");
}
...
}
Voici comment fonctionne la méthode filter
de Stream
.
L'utilisation d'instructions if est la meilleure façon (lire: la plus performante) de vérifier les conditions binaires.
L'instruction switch peut être plus rapide pour les situations plus complexes.
Un Predicate
est une forme spéciale de Function
. En fait, l'architecte de langage Java Java travaille sur un moyen d'autoriser les types primitifs génériques. Cela fera Predicate<T>
à peu près équivalent à Function<T, boolean>
(modulo le test vs appliquer le nom de la méthode).
Si une fonction (resp. Méthode) prend une ou plusieurs fonctions comme argument (s), nous l'appelons fonction d'ordre supérieur . Nous disons que nous passons le comportement à une fonction. Cela nous permet de créer de puissantes API.
String result = Match(arg).of(
Case(isIn("-h", "--help"), help()),
Case(isIn("-v", "--version"), version()),
Case($(), cmd -> "unknown command: " + cmd)
);
Cet exemple est tiré de Javaslang , une bibliothèque pour la programmation objet-fonctionnelle dans Java 8+.
Avertissement: je suis le créateur de Javaslang.