Java 8 为什么';t爪哇8';s到ntfunction<;T>;扩展函数<;T、 整数>;

Java 8 为什么';t爪哇8';s到ntfunction<;T>;扩展函数<;T、 整数>;,java-8,java,functional-interface,Java 8,Java,Functional Interface,如果我编写了ToIntFunction接口,我希望在接口中对这一事实进行编码,即它只是一个返回原语int的函数,如下所示: @FunctionalInterface public interface ToIntFunction<T> extends Function<T, Integer> { int applyAsInt(T value); @Override default Integer apply(T value) { r

如果我编写了ToIntFunction接口,我希望在接口中对这一事实进行编码,即它只是一个返回原语int的函数,如下所示:

@FunctionalInterface
public interface ToIntFunction<T> extends Function<T, Integer> {
    int applyAsInt(T value);

    @Override
    default Integer apply(T value) {
        return Integer.valueOf(applyAsInt(value));
    }
}
@functioninterface
函数的公共接口扩展了函数{
int applyAsInt(T值);
@凌驾
默认整数应用(T值){
返回Integer.valueOf(applyAsInt(value));
}
}
我想知道,Java8API设计人员选择将原语替代方案与函数完全分离是否有令人信服的原因?是否有证据表明他们考虑过这样做并决定反对?我猜类似的问题至少也适用于其他一些“特殊”功能接口,如消费者(可能是功能)和供应商(功能)

我还没有深入彻底地思考这一切的后果,所以我可能遗漏了一些东西

如果ToIntFunction(以及其他基本的通用函数接口)与函数有这种关系,它将允许在需要函数参数的地方使用它(想到的是与其他函数的组合,例如调用myFunction.compose(myIntFunction)或者避免在API中编写多个专用函数(当上述自动(取消)装箱实现足够时)


这与这个问题非常相似:但我意识到答案可能因语义原因而不同。因此,我正在为这个简单的函数的原始替代方案重新制定问题,在这个例子中,没有任何语义,仅消除了原语与包装类型,甚至消除了空包装对象的可能性。

因为这意味着所有原语操作函数都会产生自动装箱和取消装箱操作的成本


如果您不关心这对性能的影响,只需使用
函数的盒装版本

JDK 8中的接口爆炸是Java中一个小问题的产物:缺少值类型

这意味着我们不能将基元类型与泛型一起使用,因此,我们被迫使用包装器类型

换句话说,这是不可能的:

Function<String, int> myFunction;
函数myFunction;
但这是:

Function<String, Integer> myFunction;
函数myFunction;
问题在于装箱/拆箱。这可能会变得昂贵,并且由于不断需要为原始值创建包装器对象,因此难以优化处理原始数据类型的算法,反之亦然

这解释了为什么JDK 8中出现了大量接口,如
Function
IntFunction
,后者使用原语类型作为参数

在报告中讨论了这一点,表明专家组正在努力解决这一问题

lambda项目的规范负责人Brian Goetz在那里写道:

更一般地说:拥有专业化原始知识背后的哲学 流(例如IntStream)充满了令人讨厌的权衡。一方面 另一方面,它有很多丑陋的代码重复接口污染,等等。 另一方面,盒式运算的任何算法都很糟糕,而且 如果没有降低INT的故事,那就太可怕了。所以我们 在一个艰难的角落,我们正在努力不让它变得更糟

不让事情变得更糟的诀窍1是:我们并没有做到这八点 基本类型。我们在做int、long和double;所有其他的 可以用这些来模拟。可以说我们也可以去掉int, 但我们认为大多数Java开发人员还没有做好准备。对 会有人呼吁要有个性,答案是“把它放在一个盒子里” (每个专业预计约为10万至JRE 足迹。)

诀窍2是:我们使用原始流来暴露 最好在原语域中完成(排序、缩减),但不要尝试 复制您在装箱域中可以执行的所有操作。例如 正如Aleksey指出的那样,没有IntStream.into()。(如果有的话, 下一个问题是“IntCollection?IntArrayList在哪里?”? IntConcurrentSkipListMap?)的目的是许多流可以从 引用流,并最终成为原始流,但反之亦然。 这没关系,并且减少了所需的转换次数(例如,不需要 int->T的映射重载,int->T的函数没有专门化 T、 )

也许,将来当我们使用Java时,我们将能够摆脱(或者至少不再需要使用)这些接口


专家组在几个设计问题上苦苦挣扎,不仅仅是这个问题。保持向后兼容性的需要、要求或约束使事情变得困难,然后我们还有其他重要的条件,比如缺少值类型、类型擦除和检查异常。如果Java有第一个,而缺少另外两个,JDK 8的设计就可以了we’我们的情况大不相同。因此,我们都必须明白,这是一个有很多权衡的难题,EG必须在某个地方划一条线并做出决定。

@MartijnCourteaux谢谢如果你想在
到ntfunction
函数之间转换,你可以在pla中编写
到ntfunction::applyAsInt
ce期望一个
函数
@LouisWasserman是真的,但是对于许多其他的实用方法和概念来说也是如此,这些方法和概念使它成为了核心Java API。我的问题不是如何解决缺少的功能,而是为什么它首先会丢失。要清楚的是,我建议的是,它没有包括在内,因为我们是如此容易的解决办法。