使用双冒号 - 静态和非静态方法引用之间的区别

mkd*_*ve2 7 java lambda callback java-8 java-stream

编辑:我的问题在这里得到了解答.总而言之,我对非静态方法引用的使用感到困惑.功能接口和参考方法具有不同数量的参数.

回答我的问题的是评论和接受的答案.


我目前正在阅读关于流减少方法的Java教程(https://docs.oracle.com/javase/tutorial/collections/streams/reduction.html).在那里,我发现了一段我认为错误的代码,所以我做了一个更简单的代码来确保.

// B.java file
import java.util.*;

public class B 
{
  public static void main(String[] args)
  {
    List<Integer> zahlen = new LinkedList<Integer>();
    zahlen.add(1);
    zahlen.add(2);
    zahlen.add(3);
    Averager averageCollect = zahlen.stream()
      .collect(Averager::new, Averager::addcount, Averager::combine);
    System.out.println(averageCollect.average());
  }
}

// Averager.java from the official Java tutorial
public class Averager
{
    private int total = 0;
    private int count = 0;

    public double average() {
        return count > 0 ? ((double) total)/count : 0;
    }

    public void addcount(int i) { total += i; count++;}
    public void combine(Averager other) {
        total += other.total;
        count += other.count;
    }
}
Run Code Online (Sandbox Code Playgroud)

我认为这不起作用的原因是因为这条线:

Averager averageCollect = zahlen.stream()
  .collect(Averager::new, Averager::addcount, Averager::combine);
Run Code Online (Sandbox Code Playgroud)

Stream.collect(https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#collect-java.util.function.Supplier-java.util.function的Java文档中).BiConsumer-java.util.function.BiConsumer-)它表示作为第二个参数,需要一个与功能接口匹配的函数BiConsumer,它具有带两个参数的抽象方法.但Averager.addcountAverager.combine只有一个参数.

我还检查了lambda表达式:

Averager averageCollect = zahlen.stream()
  .collect(Averager::new, (a,b) -> a.addcount(b), (a,b) -> a.combine(b));
Run Code Online (Sandbox Code Playgroud)

此代码也有效,作为第二个和第三个参数,我有两个参数的函数.

为什么我上面编写的代码确实有效,即使只给出了一个参数的函数?为什么会有错误消息,当我同时改变Averager.addcountAverager.combine有两个参数也是这样吗?

public void addcount(Averager one, Integer i)
public void combine(Averager one, Averager other)
Run Code Online (Sandbox Code Playgroud)

如果我这样做,我收到以下错误消息:

B.java:12: error: no suitable method found for collect(Averager::new,Averager::addcount,Averager::combine)
      .collect(Averager::new, Averager::addcount, Averager::combine);
      ^
    method Stream.collect(Supplier,BiConsumer,BiConsumer) is not applicable
      (cannot infer type-variable(s) R#1
        (argument mismatch; invalid method reference
          cannot find symbol
            symbol:   method addcount(R#1,Integer)
            location: class Averager))
    method Stream.collect(Collector) is not applicable
      (cannot infer type-variable(s) R#2,A
        (actual and formal argument lists differ in length))
  where R#1,T,R#2,A are type-variables:
    R#1 extends Object declared in method collect(Supplier,BiConsumer,BiConsumer)
    T extends Object declared in interface Stream
    R#2 extends Object declared in method collect(Collector)
    A extends Object declared in method collect(Collector)
1 error

请帮我理解.

fin*_*nnw 6

Averager averageCollect = zahlen.stream()
  .collect(Averager::new, Averager::addcount, Averager::combine);
Run Code Online (Sandbox Code Playgroud)

这可以.它相当于

Averager averageCollect = zahlen.stream()
  .collect(() -> new Averager(),
           (myAverager, n) -> myAverager.addcount(n),
           (dst, src) -> dst.combine(src))
Run Code Online (Sandbox Code Playgroud)

请记住,每个非静态方法都有一个隐藏this参数.在这种情况下,它(正确地)将它绑定到accumulatorcombiner回调的第一个参数.

它也适用于静态方法,例如:

public static void addcount(Averager a, int i) {
    a.total += i;
    a.count++;
}
public static void combine(Averager dst, Averager src) {
    dst.total += src.total;
    dst.count += src.count;
}
Run Code Online (Sandbox Code Playgroud)

希望能让它更清楚地发生什么.

但是没有必要改变代码.