Java 8 lambdas, Function.identity() or t->t
I have a question regarding the usage of the Function.identity()
method.
Imagine the following code:
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.
Is there any reason why you should use Function.identity()
instead of str->str
(or vice versa). I think that the second option is more readable (a matter of taste of course). But, is there any "real" reason why one should be preferred?
As of the current JRE implementation, Function.identity()
will always return the same instance while each occurrence of identifier -> identifier
will not only create its own instance but even have a distinct implementation class. For more details, see here.
The reason is that the compiler generates a synthetic method holding the trivial body of that lambda expression (in the case of x->x
, equivalent to return identifier;
) and tell the runtime to create an implementation of the functional interface calling this method. So the runtime sees only different target methods and the current implementation does not analyze the methods to find out whether certain methods are equivalent.
So using Function.identity()
instead of x -> x
might save some memory but that shouldn’t drive your decision if you really think that x -> x
is more readable than Function.identity()
.
You may also consider that when compiling with debug information enabled, the synthetic method will have a line debug attribute pointing to the source code line(s) holding the lambda expression, therefore you have a chance of finding the source of a particular Function
instance while debugging. In contrast, when encountering the instance returned by Function.identity()
during debugging an operation, you won’t know who has called that method and passed the instance to the operation.
In your example there is no big difference between str -> str
and Function.identity()
since internally it is simply t->t
.
But sometimes we can't use Function.identity
because we can't use a Function
. Take a look here:
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
this will compile fine
int[] arrayOK = list.stream().mapToInt(i -> i).toArray();
but if you try to compile
int[] arrayProblem = list.stream().mapToInt(Function.identity()).toArray();
you will get compilation error since mapToInt
expects ToIntFunction
, which is not related to Function
. Also ToIntFunction
doesn't have identity()
method.
From the JDK source:
static <T> Function<T, T> identity() {
return t -> t;
}
So, no, as long as it is syntactically correct.