J'ai une question concernant l'utilisation de la méthode Function.identity()
.
Imaginez le code suivant:
Arrays.asList("a", "b", "c")
.stream()
.map(Function.identity()) // <- This,
.map(str -> str) // <- is the same as this.
.collect(Collectors.toMap(
Function.identity(), // <-- And this,
str -> str)); // <-- is the same as this.
Y a-t-il une raison pour laquelle vous devriez utiliser Function.identity()
au lieu de str->str
(ou inversement). Je pense que la deuxième option est plus lisible (une question de goût bien sûr). Mais, y a-t-il une "vraie" raison pour laquelle on devrait être préféré?
À partir de l'implémentation JRE actuelle, Function.identity()
renverra toujours la même instance, tandis que chaque occurrence de identifier -> identifier
créera non seulement sa propre instance mais aura même une classe d'implémentation distincte. Pour plus de détails, voir ici .
La raison en est que le compilateur génère une méthode synthétique contenant le corps trivial de cette expression lambda (dans le cas de x->x
, équivalent à return identifier;
) et indique au moteur d'exécution de créer une implémentation de l'appelant d'interface fonctionnelle cette méthode. Ainsi, le moteur d'exécution ne voit que différentes méthodes cible et l'implémentation actuelle n'analyse pas les méthodes pour déterminer si certaines méthodes sont équivalentes.
Donc, utiliser Function.identity()
au lieu de x -> x
pourrait économiser de la mémoire, mais cela ne devrait pas vous motiver si vous pensez réellement que x -> x
est plus lisible que Function.identity()
.
Vous pouvez également considérer que lors de la compilation avec les informations de débogage activées, la méthode synthétique aura un attribut de débogage de ligne pointant vers la ou les lignes de code source contenant l'expression lambda. Par conséquent, vous avez une chance de trouver la source d'un Function
instance lors du débogage. En revanche, lorsque vous rencontrez l’instance renvoyée par Function.identity()
lors du débogage d’une opération, vous ne savez pas qui a appelé cette méthode et passé l’instance à l’opération.
Dans votre exemple, il n'y a pas de grande différence entre str -> str
et Function.identity()
puisqu'il s'agit simplement de t->t
.
Mais parfois, nous ne pouvons pas utiliser Function.identity
parce que nous ne pouvons pas utiliser un Function
. Jetez un coup d'oeil ici:
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
cela compilera bien
int[] arrayOK = list.stream().mapToInt(i -> i).toArray();
mais si vous essayez de compiler
int[] arrayProblem = list.stream().mapToInt(Function.identity()).toArray();
vous obtiendrez une erreur de compilation puisque mapToInt
s'attend à ToIntFunction
, ce qui n'est pas lié à Function
. De plus, ToIntFunction
n'a pas de méthode identity()
.
Depuis le source JDK :
static <T> Function<T, T> identity() {
return t -> t;
}
Donc, non, tant que c'est correct sur le plan syntaxique.