【发布时间】:2020-05-04 20:39:28
【问题描述】:
Java 8 添加了函数式编程结构,包括 Function 类及其关联的 identity() 方法。
这是该方法的当前结构:
// Current implementation of this function in the [JDK source][1]
static <T> Function<T, T> identity() {
return t -> t;
}
// Can be used like this
List<T> sameList = list.stream().map(Function.identity()).collect(Collectors.toList());
但是,还有另一种结构方式:
// Alternative implementation of the method
static <T> T identity(T in) {
return in;
}
// Can be used like this
List<T> sameList = list.stream().map(Function::identity).collect(Collectors.toList());
甚至还有第三种结构方式:
// Third implementation
static final Function<T, T> IDENTITY_FUNCTION = t -> t;
// Can be used like this
List<T> sameList = list.stream().map(Function.IDENTITY_FUNCTION).collect(Collectors.toList());
在这三种方法中,JDK 中实际使用的第一种方法看起来内存效率较低,因为它似乎在每次使用时都会创建一个新对象 (lambda),而第二种和第三种实现则没有。根据this SO answer 的说法,实际情况并非如此,因此最终所有三种方法在性能方面似乎都相当。
使用第二种方法允许将方法用作方法引用,这类似于在函数构造中使用了许多其他标准库方法。例如。 stream.map(Math::abs) 或 stream.map(String::toLowerCase)。
总的来说,为什么要使用第一种方法,它看起来(尽管最终不是)性能较差并且与其他示例不同?
【问题讨论】:
-
@AndyTurner 我不认为他们是说那些是相同的,而是对于给定的实现(身份作为具有签名
T(T)的函数),这将是使用它。 -
您的标题与您的问题不符。
-
您尝试您的“第三次实施”了吗?
-
static int Math.abs(int)和String String::toLowerCase()早于 lambdas,因此无法更改,此外这些方法也可以直接调用,而不仅仅是作为方法引用。相比之下,<T> T Function::identity(T in)是新的,没有人会直接调用它(有什么意义?)。 -
您提到了用于流的样式,因此值得指出的是,尽管没有正式指定任何地方,但我们鼓励对 的方法使用静态导入提供功能接口的实现。所以我们可以用
toList()代替Collectors.toList(),而不是Comparator.compare(..)compare(...)。这允许像.map(String::length).collect(groupingBy(identity(), counting()));一样编写流。在该示例中,IMO 简单identity()比您提到的Function::identity简单。
标签: java java-8 functional-programming functional-interface