Java'reduceLeft'签名/下限类型参数

Cla*_*oft 6 java scala type-variables bounded-wildcard

以下签名在Scala中有效且常用:

trait Collection[A] {
    def reduceLeft [B >: A] (f: (B, A) => B): B
}
Run Code Online (Sandbox Code Playgroud)

但是,由于Java中>:的Scala是等效的super,我转换此签名的第一个想法(用函数类型替换BiFunction并使用Use-Site variance annotations aka Bounded Wildcards)将是

interface Collection<A> {
    <B super A> B reduceLeft(BiFunction<? super B, ? super A, ? extends B> mapper)
}
Run Code Online (Sandbox Code Playgroud)

但是哦,不!编译器抱怨super令牌,<B super A>因为你不能有低边界的类型变量!现在,如何在Java代码中编写此方法而不必回顾Java世界中不存在泛型的时间?


是的,我知道你认为我可以使用B extends A,但这不是一回事,正如我的实现所示:

public <R extends E> R reduceLeft(BiFunction<? super R, ? super E, ? extends R> mapper)
{
    if (this.isEmpty())
    {
        return null;
    }

    Iterator<E> iterator = this.iterator();
    R first = iterator.next(); // doesn't work, but would if R was a super-type of E (R super E)
    while (iterator.hasNext())
    {
        mapper.apply(first, iterator.next());
    }

    return first;
}
Run Code Online (Sandbox Code Playgroud)

相反,我不得不使用这个稍微受限制的版本:

public E reduceLeft(BiFunction<? super E, ? super E, ? extends E> mapper)
{
    if (this.isEmpty())
    {
        return null;
    }

    Iterator<E> iterator = this.iterator();
    E first = iterator.next();
    while (iterator.hasNext())
    {
        first = mapper.apply(first, iterator.next());
    }

    return first;
}
Run Code Online (Sandbox Code Playgroud)

Ion*_*tan 4

B >: AScala 方法定义中的约束是必要的,因为:

\n\n
    \n
  1. Scala 使用声明站点方差,并且不可变集合在它们包含的元素类型上是协变的。
  2. \n
  3. reduceLeft从概念上讲,需要返回 type 的值A,但用作A返回类型意味着在协变位置使用它,这与已经声明的方差冲突,即A必须是协变的。
  4. \n
\n\n

解决这种差异冲突的技巧是引入B泛型类型。

\n\n

现在,正如您所提到的,Java 采用了使用站点差异,因此用 Java 编写的任何集合都将是不变的。A这也意味着用作方法的返回类型(即逆变位置)没有问题。因此,下面的定义应该足够 \xe2\x80\x94 ,不需要类型B

\n\n
interface Collection<A> {\n  A reduceLeft(BiFunction<? super A, ? super A, ? extends A> reducer);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

然而,正如您所看到的,A一次为下限,然后为上限的最终效果是A基本上是不变的 \xe2\x80\x94 如果不使用向下转换,就不可能从通配符边界中受益。这意味着我们可以简化签名(与 非常相似Stream.reduce):

\n\n
interface Collection<A> {\n  A reduceLeft(BiFunction<A, A, A> reducer);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

此外,类型BiFunction<A, A, A>, 已经以名称 出现在 Java 8 中BinaryOperator<A>

\n