具有不同arities的重载方法的方法引用无效 [英] Invalid method reference for overloaded method with different arities

查看:170
本文介绍了具有不同arities的重载方法的方法引用无效的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

When trying to compile the expression Comparator.comparing(String::toLowerCase), the Java Compiler returns an error. See the following question for more information:

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

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

I have tried to reduce the problem as much as possible. In particular, I have removed almost all dependencies to other classes. The main method contains two method invocations. The first statement compiles without errors, whereas the second statement produces an error.

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; }
}

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

This is strange, because the second baz method shouldn't be applicable in this context, due to the mismatch in the number of parameters. I have taken a look at the JLS8 (15.13). However, it was no help, because the rules for method references are quite complex.

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

Q: Why is there a compilation error for the second case? Should there really be a compilation error according to the JLS? According to some comments on the other question, there is no compilation error in Netbeans.

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

For reference, I am using the JDK8 version 1.8.0-b132. If a compile the program on the command line, the compiler shows the following error message:

$ /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


推荐答案

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

JLS8 (15.13) is confusing but it does show examples similar to yours stating their are ambiguities in searching that it cannot resolve.

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

For your example Intellij says invoke(Foo::baz); is a Cyclic inference which I think has more to do with the combination of invoke needing to inferred a type as well as Foo::baz.

这可以通过给 invoke 函数提供一个类型来解决,类似于JSL(15.13.1例子)

This can be resolved by giving a type to the invoke function, similar to JSL (15.13.1 examples)


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

The search is smart enough to ignore ambiguities in which all the applicable methods (from both searches) are instance methods:

Foo。< Foo,String> invoke(Foo :: baz); - 相当于,我想使用 void 的方法 Foo 返回字符串 又名字符串baz()

Foo.<Foo,String>invoke(Foo::baz); -- equivalent to, I want to use the void method of Foo that returns a String 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; } 
}

我同意你 baz(整数) i)不是调用的有效参数,而不是将其设为静态或来自 Foo 。我想如果方法过载并且它试图推断出类型,搜索算法就会退出。因为它只使用一个方法签名。

I do agree with you that baz(Integer i) is not a valid argument to invoke with out making it static or from an instance of Foo. I guess the search algorithm just quits if the method is overloaded and it is trying to infer the type. Because it does work with just a single method signature.

这篇关于具有不同arities的重载方法的方法引用无效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆