使用双冒号 – 静态和非静态方法引用之间的差异

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

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


我目前正在阅读关于流减少方法的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 zahlen = new LinkedList(); 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; } } 

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

 Averager averageCollect = zahlen.stream() .collect(Averager::new, Averager::addcount, Averager::combine); 

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

我还检查了lambda表达式:

 Averager averageCollect = zahlen.stream() .collect(Averager::new, (a,b) -> a.addcount(b), (a,b) -> a.combine(b)); 

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

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

 public void addcount(Averager one, Integer i) public void combine(Averager one, Averager other) 

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

  B.java:12:错误:没有为collect找到合适的方法(Averager :: new,Averager :: addcount,Averager :: combine)
       .collect(Averager :: new,Averager :: addcount,Averager :: combine);
       ^
    方法Stream.collect(Supplier,BiConsumer,BiConsumer)不适用
       (不能推断出类型变量R#1
         (参数不匹配;无效的方法参考
          找不到标志
            符号:方法addcount(R#1,整数)
            位置:类Averager))
    方法Stream.collect(Collector)不适用
       (不能推断出类型变量R#2,A
         (实际和正式的参数列表长度不同))
  其中R#1,T,R#2,A是类型变量:
     R#1扩展方法collect中声明的Object(Supplier,BiConsumer,BiConsumer)
     T扩展了在接口Stream中声明的Object
     R#2扩展方法collect(Collector)中声明的Object
    方法collect(Collector)中声明的extends Object
 1错误 

请帮我理解。

 Averager averageCollect = zahlen.stream() .collect(Averager::new, Averager::addcount, Averager::combine); 

这可以。 它相当于

 Averager averageCollect = zahlen.stream() .collect(() -> new Averager(), (myAverager, n) -> myAverager.addcount(n), (dst, src) -> dst.combine(src)) 

请记住,每个非静态方法都有一个隐藏的参数。 在这种情况下,它(正确地)将它绑定到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; } 

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

但是没有必要改变代码。