【发布时间】:2019-03-03 02:34:49
【问题描述】:
为什么我应该使用 Function.identity() 当它返回相同的东西而不使用输入做任何事情或以某种方式修改输入时?
Apple apple = new Apple(10, "green");
Function<Apple, Apple> identity = Function.identity();
identity.apply(apple);
这一定有一些我无法弄清楚的实际用法。
【问题讨论】:
为什么我应该使用 Function.identity() 当它返回相同的东西而不使用输入做任何事情或以某种方式修改输入时?
Apple apple = new Apple(10, "green");
Function<Apple, Apple> identity = Function.identity();
identity.apply(apple);
这一定有一些我无法弄清楚的实际用法。
【问题讨论】:
预期用途是当您使用接受Function 的方法来映射某些内容时,您需要将输入直接映射到函数的输出(“身份”函数)。
作为一个非常简单的示例,将人员列表映射到从名称到人员的映射:
import static java.util.function.Function.identity
// [...]
List<Person> persons = ...
Map<String, Person> = persons.stream()
.collect(Collectors.toMap(Person::name, identity()))
identity() 函数只是为了方便和可读性。正如彼得在他的回答中指出的那样,您可以只使用t -> t,但我个人认为使用identity() 可以更好地传达意图,因为它没有留下解释的余地,比如想知道原作者是否忘记在那个 lambda 中进行转换。我承认这是非常主观的,并且假设读者知道 identity() 做了什么。
它可能在内存方面有一些额外的优势,因为它重用了单个 lambda 定义,而不是为此调用使用特定的 lambda 定义。我认为在大多数情况下,这种影响可能可以忽略不计。
【讨论】:
例如,您可以将其用于频率计数。
public static <T> Map<T, Long> frequencyCount(Collection<T> words) {
return words.stream()
.collect(Collectors.groupingBy(Function.identity(),
Collectors.counting());
}
在这种情况下,您说分组依据是集合中的元素(不转换它)。
就我个人而言,我觉得这个简报
import static java.util.stream.Collectors.*;
public static Map<String, Long> frequencyCount(Collection<String> words) {
return words.stream()
.collect(groupingBy(t -> t,
counting());
}
【讨论】:
identity()的实现是return t -> t
invokedynamic 并在运行时生成类
假设您有一个List<String> strings = List.of("abc", "de"),并且您想生成一个Map,其中Key 是List 的值形式,而Value 是它的长度:
Map<String, Integer> map = strings.stream()
.collect(Collectors.toMap(Function.identity(), String::length))
通常有些人认为Function.identity() 比t -> t 可读性差一些,但正如here 解释的那样,这有点不同。
【讨论】: