Java 8 a ajouté le concept d' interfaces fonctionnelles , ainsi que de nombreuses nouvelles méthodes conçues pour prendre des interfaces fonctionnelles. Les instances de ces interfaces peuvent être créées succinctement à l'aide d' expressions de référence de méthode (par exemple SomeClass::someMethod
) et d' expressions lambda (par exemple (x, y) -> x + y
).
Un collègue et moi avons des opinions divergentes sur le moment où il est préférable d'utiliser une forme ou une autre (où "meilleur" dans ce cas se résume vraiment à "le plus lisible" et "le plus conforme aux pratiques standard", car ils sont fondamentalement autrement équivalent). Plus précisément, cela implique le cas où les conditions suivantes sont toutes vraies:
- la fonction en question n'est pas utilisée en dehors d'une seule portée
- donner un nom à l'instance aide à la lisibilité (contrairement à par exemple la logique étant assez simple pour voir ce qui se passe en un coup d'œil)
- il n'y a pas d'autres raisons de programmation pour lesquelles un formulaire serait préférable à l'autre.
Mon opinion actuelle à ce sujet est que l'ajout d'une méthode privée et la référence par référence à la méthode est la meilleure approche. Il semble que c'est ainsi que la fonctionnalité a été conçue pour être utilisée, et il semble plus facile de communiquer ce qui se passe via les noms et les signatures de méthode (par exemple, "boolean isResultInFuture (Result result)" dit clairement qu'il renvoie un booléen). Il rend également la méthode privée plus réutilisable si une future amélioration de la classe veut utiliser la même vérification, mais n'a pas besoin du wrapper d'interface fonctionnelle.
La préférence de mon collègue est d'avoir une méthode qui retourne l'instance de l'interface (par exemple "Predicate resultInFuture ()"). Pour moi, cela semble que ce n'est pas tout à fait la façon dont la fonctionnalité était destinée à être utilisée, se sent un peu plus maladroite et semble qu'il est plus difficile de vraiment communiquer l'intention par le biais de la dénomination.
Pour concrétiser cet exemple, voici le même code, écrit dans les différents styles:
public class ResultProcessor {
public void doSomethingImportant(List<Result> results) {
results.filter(this::isResultInFuture).forEach({ result ->
// Do something important with each future result line
});
}
private boolean isResultInFuture(Result result) {
someOtherService.getResultDateFromDatabase(result).after(new Date());
}
}
contre.
public class ResultProcessor {
public void doSomethingImportant(List<Result> results) {
results.filter(resultInFuture()).forEach({ result ->
// Do something important with each future result line
});
}
private Predicate<Result> resultInFuture() {
return result -> someOtherService.getResultDateFromDatabase(result).after(new Date());
}
}
contre.
public class ResultProcessor {
public void doSomethingImportant(List<Result> results) {
Predicate<Result> resultInFuture = result -> someOtherService.getResultDateFromDatabase(result).after(new Date());
results.filter(resultInFuture).forEach({ result ->
// Do something important with each future result line
});
}
}
Existe-t-il une documentation ou des commentaires officiels ou semi-officiels sur le point de savoir si une approche est plus préférée, plus conforme aux intentions des concepteurs de langage ou plus lisible? À moins d'une source officielle, y a-t-il des raisons claires pour lesquelles on serait la meilleure approche?
Object::toString
). Donc ma question est plus de savoir si c'est mieux dans ce type particulier d'instance que je présente ici, que s'il existe des cas où l'un est meilleur que l'autre, ou vice versa.