Java 8中静态方法引用的限制

我正在尝试使用方法引用来捕获方法调用,并且遇到了一些限制。 这很好用:

 void capture(Function in) { } private interface Foo { String getBar(); } capture(Foo::getBar); 

但是,如果我将Foo.setBar的签名更改为以下内容:

 private interface Foo { void setBar(String bar); } capture(Foo::setBar); 

我收到一个错误:

Cannot make a static reference to the non-static method setBar(String) from the type MyTest.Foo

我不清楚限制是什么。 理想情况下,我想使用方法引用来捕获标准setter上的调用。 有没有办法做到这一点?

这里有两个问题:

  • 你正在使用Function ,它必须返回一些东西。 setBar不返回任何内容。
  • Function只接受一个输入,但是你有两个输入:你要调用setBarFoo ,以及你传递给setBarString参数。

如果您改为使用BiConsumer (它具有void返回类型和两个输入),它可以正常工作:

 static  void capture(BiConsumer in) { } 

您可以重载capture方法以具有两个签名:

 static  void capture(BiConsumer in) { } static  void capture(Function in) { } 

然后使用两个方法引用:

 capture(Foo::setBar); capture(Foo::getBar); 

Foo::getBar对应于一个接受Foo (目标对象)并返回String的函数。 接口Function可用于表示此类函数。

另一方面, Foo::setBar对应于一个带有两个参数的函数,一个是Foo (目标对象),另一个是String (第一个参数)。 匹配的接口是BiConsumer 。 这意味着你需要BiConsumer的重载:

  void capture(BiConsumer setter) { // ... } 

暴露语法糖方法参考,你应该看到,那

 Foo::getBar 

等于

 (Foo)foo -> foo.getBar() 

这是Function

 Foo::setBar 

在这个上下文中是两个变量的函数( foo和一些String str ),所以它不是一个变量的函数( Function

为了更方便的答案,您应该看到允许方法引用的位置:

  1. 引用静态方法(根本不是这种情况)
  2. 引用特定对象的实例方法(根本不是这种情况)
  3. 引用特定类型的任意对象的实例方法(本例)

    在上面的说明中有一个例子,几乎与你的情况相同。 据说,等效的lambda表达式将采用两个参数(在本例中为FooString ),这不是Function

  4. 引用构造函数(根本不是这种情况)