java.util.function.Function.identity方法的实际用途是什么?

38

当Function.identity()不对输入值进行任何操作时,返回与输入相同的内容,为什么我要使用它呢?

为什么

Apple apple = new Apple(10, "green");
Function<Apple, Apple> identity = Function.identity();
identity.apply(apple);

我一定没有想到的一些实用方法。

3个回答

37

此处使用场景是当您使用接受Function函数以映射某些内容的方法时,并且您需要将输入直接映射到函数的输出(即“identity”函数)。

一个非常简单的例子是,将人员列表映射为从名称到人员的映射:

import static java.util.function.Function.identity

// [...]

List<Person> persons = ...
Map<String, Person> = persons.stream()
        .collect(Collectors.toMap(Person::name, identity()))
identity()函数仅仅是为了方便和可读性。正如Peter在他的回答中所指出的,你可以直接使用t -> t,但我个人认为使用identity()更好地传达了意图,因为它不留下任何解释的余地,比如怀疑原作者是否忘记在该lambda中进行转换。尽管我承认这是高度主观的,并且假设读者知道 identity()的作用。
可能它在内存方面有一些额外的优点,因为它重用了单个lambda定义,而不是针对此调用具有特定的lambda定义。但我认为在大多数情况下,这种影响可能是可以忽略不计的。

15
你可以将其用于频率计数,例如。
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());
}

@Eugene identity() 的实现是 return t -> t - Mark Rotteveel
4
@MarkRotteveel没错,我的意思是这个 - Eugene
@Dici,顺便说一下,这是他们最初想采用的一种合法策略(Brian Goetz有关于此的讨论)-但他们选择不这样做。他们选择使用“invokedynamic”并在运行时生成类。 - Eugene
@Dici 它是100%正确的,至少在当前的实现下,非常容易证明... - Eugene
@Holger 嗯,有趣 - Dici
显示剩余2条评论

4
假设您有一个List<String> strings = List.of("abc", "de"),您希望生成一个Map,其中Key是该列表中的值,而Value是它们的长度:
 Map<String, Integer> map = strings.stream() 
        .collect(Collectors.toMap(Function.identity(), String::length)) 

一般来说,有些人认为Function.identity()比如t -> t不那么易读,但是根据这里解释,实际上两者还是有所区别的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接