У меня вопрос относительно использования метода Function.identity()
.
Представьте следующий код:
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.
Есть ли причина, по которой вам следует использовать Function.identity()
вместо str->str
(или наоборот). Я думаю, что второй вариант более читабельный (конечно, вопрос вкуса). Но есть ли "настоящая" причина, почему нужно быть предпочтительным?
Ответ 1
Как и в текущей реализации JRE, Function.identity()
всегда будет возвращать один и тот же экземпляр, в то время как каждое вхождение identifier -> identifier
не только создаст свой собственный экземпляр, но даже будет иметь отдельный класс реализации. Подробнее см. здесь.
Причина заключается в том, что компилятор генерирует синтетический метод, содержащий тривиальное тело этого лямбда-выражения (в случае x->x
, эквивалентное return identifier;
), и сообщает исполняющей среде создать реализацию функционального интерфейса, вызывающего это метод. Таким образом, среда выполнения видит только разные целевые методы, и текущая реализация не анализирует методы, чтобы выяснить, являются ли определенные методы эквивалентными.
Поэтому использование Function.identity()
вместо x -> x
может сэкономить некоторую память, но это не должно принимать ваше решение, если вы действительно считаете, что x -> x
более читабельно, чем Function.identity()
.
Вы также можете подумать, что при компиляции с включенной информацией об отладке синтетический метод будет иметь атрибут отладки линии, указывающий на строку исходного кода, содержащую лямбда-выражение, поэтому у вас есть шанс найти источник определенного Function
при отладке. В отличие от этого, когда вы сталкиваетесь с экземпляром, возвращаемым Function.identity()
во время отладки операции, вы не знаете, кто вызвал этот метод и передал экземпляр операции.
Ответ 2
В вашем примере нет большой разницы между str -> str
и Function.identity()
, так как внутри это просто t->t
.
Но иногда мы не можем использовать Function.identity
. Взгляните сюда
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
это скомпилирует штраф
int[] arrayOK = list.stream().mapToInt(i -> i).toArray();
но если вы попытаетесь скомпилировать
int[] arrayProblem = list.stream().mapToInt(Function.identity()).toArray();
вы получите ошибку компиляции, так как mapToInt
ожидает ToIntFunction
, которая не связана с Function
. Также ToIntFunction
не имеет метода identity()
.
Ответ 3
Из источника JDK:
static <T> Function<T, T> identity() {
return t -> t;
}
Итак, нет, если это синтаксически корректно.