Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/311.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Java中,为什么Function.identity()是静态方法而不是其他方法?_Java_Java 8_Functional Programming_Functional Interface - Fatal编程技术网

在Java中,为什么Function.identity()是静态方法而不是其他方法?

在Java中,为什么Function.identity()是静态方法而不是其他方法?,java,java-8,functional-programming,functional-interface,Java,Java 8,Functional Programming,Functional Interface,Java8添加了函数式编程构造,包括函数类及其关联的标识方法 以下是此方法的当前结构: // 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().

Java8添加了函数式编程构造,包括函数类及其关联的标识方法

以下是此方法的当前结构:

// 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());
甚至还有第三种方法可以构建它:

// 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,而第二种和第三种实现则没有。根据研究,事实并非如此,因此最终这三种方法在性能方面似乎相对相当

使用第二种方法可以将该方法用作方法引用,这与函数构造中使用的其他许多标准库方法类似。例如stream.mapMath::abs或stream.mapString::toLowerCase

总的来说,为什么要使用第一种方法,它看起来最终性能并没有下降,并且与其他示例不同;DR使用Function.identity只创建一个对象,因此非常节省内存

第三个实现不编译,因为t是未定义的,所以这不是一个选项

在第二个实现中,每次编写Function::identity时,都会创建一个新的对象实例

在第一个实现中,无论何时调用Function.identity,都会返回同一lambda对象的实例

这是很容易看到自己。首先在同一个类中创建两个identity方法,将它们重命名为identity1和identity2,以使它们可以单独识别

static <T> Function<T, T> identity1() {
    return t -> t;
}

static <T> T identity2(T in) {
    return in;
}
反复调用test方法,查看每个方法是否都获得了一个新的对象实例,我的代码是否在名为test的类中

如您所见,调用Test.identity1的多个语句都获得相同的对象,但是使用Test::identity2的多个语句都获得不同的对象

的确,重复执行同一条语句会得到循环结果中看到的相同对象,但这与从不同语句获得的结果不同


结论:使用Test.identity1只创建一个对象,因此它比使用Test::identity2更节省内存。

@AndyTurner我认为他们并不是说它们是相同的,而是将给定的实现标识作为带有签名TT的函数,这就是使用它的方式。你的标题与你的问题不一致。你是否尝试了第三个实现?静态int Math.absint和String String::toLowerCase早于lambdas,因此它不能更改,此外,这些方法也可以直接调用,而不是仅作为方法引用。相比之下,T Function::identityT In将是新的,没有人会直接调用它。您提到了一种用于流的样式,因此值得指出的是,尽管没有在任何地方正式指定,我们被鼓励对提供功能接口实现的方法使用静态导入。因此,我们可以编写toList而不是Comparator.toList来代替Collectors.toList。。比较这允许像.mapString::length.collectgroupingByidentity,counting;那样写入流;。在那个例子中,IMO simple identity比您提到的Function::identity更简单。谢谢!您知道为什么方法引用每次都创建一个新对象吗?这是语言规范所要求的,还是Oracle的JVM或您测试的任何JVM的产物?@Mark我认为规范中没有这方面的内容。一个特定的书面方法引用在第一次使用时创建一个可重用的lambda对象,这是一个JVM实现决策。Oracles API中Function.identity的实现完全依赖于此。其他实现可能不让JVM来做,在这种情况下,他们可能会实现Function.identity来自己做这样的记忆。这在中进行了解释,但如中所述,如果某个特定实现不重用为无状态lambda生成的对象,那么它一定有这样做的原因,换句话说,我们不应该抵制,Function.identity本身进行记忆将是一件值得怀疑的事情。有趣的是,它并不遵循Function.identity的模式,而是打算用作Object::isNull。它被添加到同一版本中,其文档甚至明确表示它打算与方法引用一起使用,就像OP的第二个变体一样。