我们有一个功能接口Functional
(为简洁起见,我省略了实现并简化了案例):
@FunctionalInterface
public interface Functional<E> {
void perform(E e);
default <T extends Number> void method(E e, T t) { }
default <T extends Number> void method(E e, Function<E, T> function) { }
}
还有一段简单的代码:
Functional<String> functional = (string) -> {};
functional.method("string", (string) -> 1);
由于将lambda作为参数传递,为什么方法method()
不明确?这应该很容易区分。
Eclipse :
方法
method(String, Function<String,Integer>)
对于类型Functional<String>
来说是不明确的
这也可以在 IntelliJIdea 上重现。
Javac输出(感谢@AndyTurner):
Main.java:21: error: reference to method is ambiguous
functional.method("string", (string) -> 1);
^
both method <T#1>method(E,T#1) in Functional and method <T#2>method(E,Function<E,T#2>) in Functional match
where T#1,E,T#2 are type-variables:
T#1 extends Number declared in method <T#1>method(E,T#1)
E extends Object declared in interface Functional
T#2 extends Number declared in method <T#2>method(E,Function<E,T#2>)
和
Main.java:21: error: incompatible types: cannot infer type-variable(s) T
functional.method("string", (string) -> 1);
^
(argument mismatch; Number is not a functional interface)
where T,E are type-variables:
T extends Number declared in method <T>method(E,T)
E extends Object declared in interface Functional
编辑:一个有趣的事实。当我将default <T extends Number>
替换为<T>
时,它可以工作。 T
似乎无法扩展Number
,Throwable
等...
default <T> void method(E e, T t) { }
default <T> void method(E e, Function<E, T> function) { }
编辑2 :当我将通用类型T
设置为接口声明时,它也可以正常工作:
@FunctionalInterface
public interface Functional<E, T extends Number> {
void get(E e);
default void method(E e, Function<E, T> function) { }
default void method(E e, T t) { }
}
答案 0 :(得分:6)
有多个票证(here,here和here)包含相似的代码片段。这些票证被解析为“不是问题”,解释如下:
表达式可能与目标类型兼容,具体取决于 遵守以下规则:
- [...]
- lambda表达式或方法引用表达式可能是 如果类型变量是类型,则与类型变量兼容 候选方法的参数。
因此,在这种情况下,两种方法method
都可能兼容。
此外,lambda (string) -> 1
与适用性无关,因为:
自变量表达式被认为与 可能适用的方法
m
,除非它具有以下之一 表格
- [...]
- 如果
m
是通用方法,并且方法调用不提供 显式类型参数,显式类型的lambda表达式或 对应目标的精确方法参考表达式 type(从m的签名派生)是m
的类型参数。
最后:
由于
method
具有类型参数,因此lambda为 作为参数传递时,lambda从适用性检查中跳过 -意味着两者都适用-因此模棱两可。
可能的解决方法-调用方法时强制转换参数:
functional.method("string", (Function<String, Number>) (string) -> 1);