【问题标题】:Limits of static method references in Java 8Java 8 中静态方法引用的限制
【发布时间】:2014-05-21 21:32:18
【问题描述】:

我正在尝试使用方法引用来捕获方法调用,但遇到了一些限制。这工作正常:

<T> void capture(Function<T, ?> 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

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

【问题讨论】:

  • 这甚至是 Java 吗?还是 Java 8 中的新语法?
  • 能发个错误吗?
  • @AnubianNoob 这确实是Java8s的方法引用等等……
  • 呃,什么是“静态”?我没有看到 static 修饰符?
  • @meriton:方法引用实际上是静态的,因为它就像一个 lambda 表达式,它接受 Foo 并调用该引用的方法 on

标签: java java-8 method-reference


【解决方案1】:

这里有两个问题:

  • 你正在使用Function,它必须返回一些东西。 setBar 不返回任何内容。
  • Function 只接受一个输入,但您有 两个 输入:您将调用 setBarFoo 和您将传递给 @987654327 的 String 参数@。

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

static <T, U> void capture(BiConsumer<T, U> in) {
}

您可以重载 capture 方法以同时拥有两个签名:

static <T, U> void capture(BiConsumer<T, U> in) { }
static <T> void capture(Function<T, ?> in) { }

然后使用两个方法引用:

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

【讨论】:

  • 惊人的快速响应。谢谢!一旦允许我,我会接受你的回答。
  • @JoshStone:很高兴这很有意义。我对 Java 8 的东西做的不多,也没有写过关于它的文章,所以需要一段时间来磨练如何解释这些东西。让我知道您是否希望我扩展任何内容。
  • @JoshStone 你要记住,尽管提供所有可能的重载(尤其是当你遇到类似的arity 时)会因为在运行时擦除泛型而给你带来麻烦。目前,我相信当涉及到void 时,甚至会有一些类似的问题,但我认为针对该特定问题的修复工作正在进行中。
【解决方案2】:

Foo::getBar 对应于一个接受Foo(目标对象)并返回String 的函数。接口Function&lt;Foo, String&gt;可以用来表示这样的功能。

另一方面,Foo::setBar 对应于一个接受两个参数的函数,一个Foo(目标对象)和一个String(第一个参数)。匹配接口为BiConsumer&lt;Foo, String&gt;。这意味着您需要为BiConsumer 重载:

<T, U> void capture(BiConsumer<T, U> setter) {
    // ...
}

【讨论】:

    【解决方案3】:

    公开语法糖方法参考,你应该看到,那个

    Foo::getBar
    

    等于

    (Foo)foo -> foo.getBar()
    

    这是Function &lt;Foo, String&gt;

    但是

    Foo::setBar
    

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

    你应该看到更方便的答案,method references 是允许的:

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

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

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

    【讨论】:

      猜你喜欢
      • 2018-11-25
      • 2017-07-01
      • 2015-02-21
      • 2023-03-09
      • 1970-01-01
      • 2016-03-02
      • 2019-03-10
      • 2014-11-05
      • 2013-06-30
      相关资源
      最近更新 更多