Lambdas de Java 8, Function.identity() o t->t
Tengo una pregunta sobre el uso del Function.identity()
método.
Imagina el siguiente código:
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.
¿Hay alguna razón por la que deberías usar Function.identity()
en lugar de str->str
(o viceversa)? Creo que la segunda opción es más legible (cuestión de gustos, claro). Pero, ¿existe alguna razón "real" por la que se debería preferir uno?
A partir de la implementación actual de JRE, Function.identity()
siempre devolverá la misma instancia, mientras que cada aparición de identifier -> identifier
no solo creará su propia instancia sino que incluso tendrá una clase de implementación distinta. Para obtener más detalles, consulte aquí .
La razón es que el compilador genera un método sintético que contiene el cuerpo trivial de esa expresión lambda (en el caso de x->x
, equivalente a return identifier;
) y le indica al motor de ejecución que cree una implementación de la interfaz funcional que llama a este método. Por lo tanto, el tiempo de ejecución solo ve diferentes métodos de destino y la implementación actual no analiza los métodos para descubrir si ciertos métodos son equivalentes.
Por lo tanto, usar Function.identity()
en lugar de x -> x
podría ahorrar algo de memoria, pero eso no debería influir en su decisión si realmente cree que x -> x
es más legible que Function.identity()
.
También puede considerar que al compilar con la información de depuración habilitada, el método sintético tendrá un atributo de depuración de línea que apunta a las líneas del código fuente que contienen la expresión lambda, por lo tanto, tiene la posibilidad de encontrar la fuente de una Function
instancia particular durante la depuración. . Por el contrario, cuando encuentre la instancia devuelta Function.identity()
durante la depuración de una operación, no sabrá quién llamó a ese método y pasó la instancia a la operación.
En tu ejemplo no hay gran diferencia entre str -> str
y Function.identity()
ya que internamente es simplemente t->t
.
Pero a veces no podemos usarlo Function.identity
porque no podemos usar un archivo Function
. Échale un vistazo aquí:
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
esto se compilará bien
int[] arrayOK = list.stream().mapToInt(i -> i).toArray();
pero si intentas compilar
int[] arrayProblem = list.stream().mapToInt(Function.identity()).toArray();
Obtendrá un error de compilación ya que mapToInt
se espera ToIntFunction
, que no está relacionado con Function
. Tampoco ToIntFunction
tiene identity()
método.
De la fuente JDK :
static <T> Function<T, T> identity() {
return t -> t;
}
Entonces no, siempre y cuando sea sintácticamente correcto.