具有不同arities的重载方法的方法引用无效

nos*_*sid 7 java type-inference java-8 method-reference

尝试编译表达式时Comparator.comparing(String::toLowerCase),Java编译器返回错误.有关更多信息,请参阅以下问题:

为什么Comparator.comparing不能与String :: toLowerCase方法引用一起使用?


我试图尽可能地减少这个问题.特别是,我已经删除了几乎所有依赖项到其他类.的主要方法包括两个方法调用.第一个语句编译时没有错误,而第二个语句产生错误.

interface Fun<T, R> { R apply(T t); }

public final class Foo {
    public static void main(String... args) {
        invoke(Foo::bar); // OK
        invoke(Foo::baz); // ERROR
    }
    private static <T, U> void invoke(Fun<T, U> f) { }
    private String bar() { return null; }
    private String baz() { return null; }
    private String baz(Integer i, Integer j) { return null; }
}
Run Code Online (Sandbox Code Playgroud)

这很奇怪,因为第二个baz方法不适用于此上下文,因为参数数量不匹配.我看了JLS8(15.13).但是,它没有帮助,因为方法引用的规则非常复杂.

问:为什么第二种情况会出现编译错误?根据JLS真的会出现编译错误吗?根据对另一个问题的一些评论,Netbeans中没有编译错误.


作为参考,我使用的是JDK8版本1.8.0-b132.如果在命令行上编译程序,编译器将显示以下错误消息:

$ /opt/jdk8/bin/javac Foo.java
Foo.java:6: error: incompatible types: cannot infer type-variable(s) T,U
        invoke(Foo::baz); // ERROR
              ^
    (argument mismatch; invalid method reference
      no suitable method found for baz(Object)
          method Foo.baz() is not applicable
            (actual and formal argument lists differ in length)
          method Foo.baz(Integer,Integer) is not applicable
            (actual and formal argument lists differ in length))
  where T,U are type-variables:
    T extends Object declared in method <T,U>invoke(Fun<T,U>)
    U extends Object declared in method <T,U>invoke(Fun<T,U>)
Foo.java:6: error: invalid method reference
        invoke(Foo::baz); // ERROR
               ^
  non-static method baz() cannot be referenced from a static context
2 errors
Run Code Online (Sandbox Code Playgroud)

Sco*_*ott 5

JLS8(15.13)令人困惑,但它确实显示了类似于你的例子,说明它们在搜索中的含糊不清,无法解决.

对于你的例子,Intellij说invoke(Foo::baz);是一个循环推理,我认为它更多地与invoke需要推断类型的组合有关Foo::baz.

这可以通过给invoke函数赋予类型来解决,类似于JSL(15.13.1示例)

搜索足够智能,可以忽略所有适用方法(来自两个搜索)都是实例方法的歧义:

Foo.<Foo,String>invoke(Foo::baz);- 相当于,我想使用返回voidFooString aka 方法String baz()

interface Fun<T, R> { R apply(T t); }
interface Fun2<T,U,R> { R apply(T t, U u); }

public final class Foo {
    public static void main(String... args) {
        invoke(Foo::bar); // OK
        Foo.<Foo,String>invoke(Foo::baz); // NO ERROR
        Fun2<Foo, Integer, String> f2 = Foo::baz; // Overloaded method baz
    }
    private static <T, U> void invoke(Fun<T, U> f) { }
    private String bar() { return null; }
    private String baz() { return null; }
    private String baz(Integer i) { return null; } 
}
Run Code Online (Sandbox Code Playgroud)

我同意你的意见,这baz(Integer i)不是一个有效的论据invoke,不能使它静态或从一个实例Foo.我想搜索算法只是在方法过载并且它试图推断出类型时才退出.因为它只使用一个方法签名.