【发布时间】:2019-05-07 14:31:51
【问题描述】:
让我们有一个函数式接口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
编辑:一个有趣的事实。当我用<T> 替换default <T extends Number> 时,它可以工作。 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) { }
}
【问题讨论】:
-
我希望
<T extends Number>可以工作,而<T>会失败,因为它可以与任何参数兼容。有趣的是,情况恰恰相反。作为记录,如果第二种方法有extends Number,这没有什么区别。 -
@shmosel
Function严格小于Object,但Number和Function是“并列”的。 (并且可能有一个扩展Number并实现Function的类。) -
@LouisWasserman 这样的类永远无法实现/实例化为 lambda。
-
当您从变量
Function<String, ? extends Number>引用 lambda 时,它似乎也可以工作。似乎很奇怪,它无法正确推断内联时使用哪种方法。 -
有趣的是,提供显式类型参数会使歧义消失,即
functional.<Number>method("string", (string) -> 1);工作正常。
标签: java generics exception lambda java-8