web-dev-qa-db-fra.com

Java 8 lambdas, Function.identity () ou t-> t

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é?

198
user4464654

À 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.

257
Holger

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().

79
Pshemo

Depuis le source JDK :

static <T> Function<T, T> identity() {
    return t -> t;
}

Donc, non, tant que c'est correct sur le plan syntaxique.

39
JasonN