使用实例类型对实例方法的方法引用

Method reference to instance method using instance type

我指的是 this 文章,其中指出我们可以使用两种方式引用实例方法:

  1. 使用实例

    obj::instanceMethod
    
  2. 使用实例类型

    ObjectType::instanceMethod
    

首先我用我的简单例子很容易验证:

class DummyConsumer
{
    public void consume(String a)
    {
        System.out.println("Counsumed " + a);
    }
}

DummyConsumer d = new DummyConsumer();
Consumer<String> c1 = d::consume;     //method reference
Consumer<String> c2 = (s) -> d.consume(s);  //lambda expression
c1.accept("s");
c2.accept("d");

但我无法对 ObjectType::instanceMethod 做同样的事情。该页面上给出的示例让我很困惑,如下所示:

class Shipment {
  public double calculateWeight() { return 0d; }
}

public List<Double> calculateOnShipments(List<Shipment> l, Function<Shipment, Double> f) {
    List<Double> results = new ArrayList<>();
    for(Shipment s : l) {
      results.add(f.apply(s));
    }
    return results;
}
calculateOnShipments(l, s -> s.calculateWeight()); //lambda expression
calculateOnShipments(l, Shipment::calculateWeight); //method reference

请注意上面最后一行的 Shipment::calculateWeight。有人可以帮我用我的 Consumer 示例来模仿吗?

之所以可以在没有实例的情况下使用 ObjectType::instanceMethod,是因为该方法引用表示接受 ObjectType 作为参数的方法,后跟 instanceMethod 的参数。

class A {
    public void f(String s) {}
}

在这里,您可以将 A::f 视为代表这样的 "static" 方法:

public static void f(A a, String s) {}

因此在您的示例中,您需要一个 BiConsumer 来表示一个接受两个参数且不返回任何内容的方法:

BiConsumer<DummyConsumer, String> c = DummyConsumer::consume;

Shipment的情况下,Shipment::calculateWeight代表一个"static"方法,像这样:

public static double calculateWeight(Shipment s) { ... }

这就是为什么Shipment::calculateWeight可以用Function<Shipment, Double>表示的原因。

所以一般来说,你只需要先弄清楚一个方法引用代表的是一个什么样的方法,然后找到一个代表这种方法的函数式接口就可以了。有时,您需要自己创建一个函数式界面!