Java8流并行减少BiFunction累加器

时间:2014-10-20 23:30:22

标签: java java-8 reduce java-stream binary-operators

我有一个学习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说

方法匹配函数参数以减少,所以我们可以使用方法引用。

抱歉,如果问题很简单,但任何帮助都非常感谢..

来自委内瑞拉的最好问候

1 个答案:

答案 0 :(得分:2)

是的,这里有一个关于使用这种方法引用时参数移位方式的细微之处,特别是“未绑定”方法引用。

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

BiFunction<U, ? super T, U> accumulator

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

U apply(U, T)

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

ImmutableAverager accept(int i)

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

newAverager = oldAverager.accept(i);

实际上,accept方法实际上需要两个参数,即使它看起来不像它。第一个是接收器,类型为ImmutableAverager,第二个类型为int。方法调用语法使它看起来像接收器有一些特殊的东西,但实际上没有。这就好像这是一个静态方法,如下所示:

newAverager = accept(oldAverager, i);

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

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

我只在这里展示第二个参数。这必须是BiFunction,其UT参数并返回U,如上所示。如果你查看accept方法并将接收器视为特殊而不是普通的参数,它将采用类型为ImmutableAverager的参数和类型为int的参数,并返回一个ImmutableAverager。因此,U被推断为ImmutableAveragerT被推断为Integer(从int加框),此方法参考可用。

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