0

我正在学习 Java 8。我要面对的最困难的事情是 Parallel Reduction。这是我正在研究的用户@Stuart Marks 的示例代码。

class ImmutableAverager 
{
    private final int total;
    private final int count;
    public ImmutableAverager(){this.total = 0;this.count = 0;}
   public ImmutableAverager(int total, int count)
   {
      this.total = total;
      this.count = count;
   }
   public double average(){return count > 0 ? ((double) total) / count : 0;}
   public ImmutableAverager accept(final int i)
   {
       return new ImmutableAverager(total + i, count + 1);
   }
   public ImmutableAverager combine(final ImmutableAverager other)
   {
       return new ImmutableAverager(total + other.total, count + other.count);
   }  

通话

public static void main(String[] args)     
{
       System.out.println(Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
        .parallel()
        .reduce(new ImmutableAverager(), 
                ImmutableAverager::accept,
                ImmutableAverager::combine)
        .average());    
}

这会产生正确的结果,但后来我检查了 reduce 方法的签名

<U> U reduce(U identity,
             BiFunction<U, ? super T, U> accumulator,
             BinaryOperator<U> combiner);

如果代码类似于:

.reduce(new ImmutableAverager(),(a,b)->a.accept(b),(a,b)->a.combine(b))

我不明白如何:

 ImmutableAverager::accept

可以转换成BiFunction

我的理解是这样的:

ImmutableAverager::accept

是把它转换成类似的东西

(ImmutableAverage a)->a.accept(); //but this is a function with 1 parameter not with 2 parameters.

ImmutableAverager::merge

可以转换成BinaryOperator. 我的朋友@Stuart Marks 说

这些方法匹配函数参数以减少,因此我们可以使用方法引用。

4

1 回答 1

3

是的,当使用这种方法引用,特别是“未绑定”方法引用时,参数的转移方式有一个微妙之处。

让我们看看 的第二个参数reduce()。它想要

BiFunction<U, ? super T, U> accumulator

所以它的抽象方法的签名是:

U apply(U, T)

(为简洁起见,省略了通配符)。该示例使用了方法引用ImmutableAverager::accept,其签名为:

ImmutableAverager accept(int i)

看起来这不起作用,因为 aBiFunction需要两个参数,而该accept方法只需要一个。但是请注意,该accept方法是类上的实例方法ImmutableAverager,因此它隐含地接受了一个“接收者”,即调用此方法的对象。对该方法的普通调用可能如下所示:

newAverager = oldAverager.accept(i);

所以真的,该accept方法实际上有两个参数,即使它看起来不像。第一个是接收器,它是 type ImmutableAverager,第二个是 type int。方法调用语法使接收者看起来有些特殊,但实际上并没有。就好像这是一个像这样调用的静态方法:

newAverager = accept(oldAverager, i);

现在让我们看看它是如何与reduce调用一起工作的。有问题的代码是,

reduce(..., ImmutableAverager::accept, ...)

我在这里只展示第二个论点。这需要是 a BiFunction,它接受 and 的参数UT返回 a U,如上所示。如果您查看该accept方法并将接收者视为普通参数而不是特殊的东西,它会接受一个类型ImmutableAverager的参数和一个类型的参数int,并返回一个ImmutableAverager. So Uis inferred to be ImmutableAveragerand Tis inferred to be Integer(boxed from int),这里的方法参考有效。

关键是,对于未绑定的方法引用,方法引用是实例方法,但方法是使用类名而不是实际实例指定的。当这种情况发生时,接收者变成方法调用的第一个参数。

于 2014-10-21T00:05:36.800 回答