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)
。
总体上,为什么要使用第一种方法,尽管它[
TL; DR使用Function.identity()
仅创建一个对象,因此具有很高的内存效率。
T
未定义,所以这不是一个选择。在第二种实现中,每次您编写Function::identity
时,都会创建一个
new对象实例。
在第一个实现中,每当调用Function.identity()
时,都会返回same
lambda对象的实例。很容易看到自己。首先在同一类中创建两个identity
方法,因此将它们重命名为identity1
和identity2
,以使其分别可识别。static <T> Function<T, T> identity1() {
return t -> t;
}
static <T> T identity2(T in) {
return in;
}
编写一个接受test
并打印对象的Function
方法,因此我们可以看到它的唯一标识,如哈希码所示。
static <A, B> void test(Function<A, B> func) { System.out.println(func); }
反复调用test
方法以查看每个对象是否都获得一个新的对象实例((我的代码在名为
Test
的类中)>]。
test(Test.identity1());
test(Test.identity1());
test(Test.identity1());
test(Test::identity2);
test(Test::identity2);
for (int i = 0; i < 3; i++)
test(Test::identity2);
输出
Test$$Lambda$1/0x0000000800ba0840@7adf9f5f
Test$$Lambda$1/0x0000000800ba0840@7adf9f5f
Test$$Lambda$1/0x0000000800ba0840@7adf9f5f
Test$$Lambda$2/0x0000000800ba1040@5674cd4d
Test$$Lambda$3/0x0000000800ba1440@65b54208
Test$$Lambda$4/0x0000000800ba1840@6b884d57
Test$$Lambda$4/0x0000000800ba1840@6b884d57
Test$$Lambda$4/0x0000000800ba1840@6b884d57
如您所见,多个调用都获得相同的对象,但是使用Test.identity1()
的statements
Test::identity2
的多个statements都获得了不同的对象。确实,same
语句的repeated执行得到相同的对象(从循环的结果中可以看出),但这与从different语句获得的结果不同。结论:
使用Test.identity1()
仅创建一个对象,因此比使用Test::identity2
具有更高的内存效率。