假设我有一个通用接口:
interface MyComparable<T extends Comparable<T>> {
public int compare(T obj1, T obj2);
}
方法sort
:
public static <T extends Comparable<T>>
void sort(List<T> list, MyComparable<T> comp) {
// sort the list
}
我可以调用此方法并将lambda表达式作为参数传递:
List<String> list = Arrays.asList("a", "b", "c");
sort(list, (a, b) -> a.compareTo(b));
这样可以正常工作。
但是现在如果我使接口非泛型,并且方法通用:
interface MyComparable {
public <T extends Comparable<T>> int compare(T obj1, T obj2);
}
public static <T extends Comparable<T>>
void sort(List<T> list, MyComparable comp) {
}
然后调用它:
List<String> list = Arrays.asList("a", "b", "c");
sort(list, (a, b) -> a.compareTo(b));
它无法编译。它在lambda表达式中显示错误:
“目标方法是通用的”
好的,当我使用javac
编译它时,它显示以下错误:
SO.java:20: error: incompatible types: cannot infer type-variable(s) T#1
sort(list, (a, b) -> a.compareTo(b));
^
(argument mismatch; invalid functional descriptor for lambda expression
method <T#2>(T#2,T#2)int in interface MyComparable is generic)
where T#1,T#2 are type-variables:
T#1 extends Comparable<T#1> declared in method <T#1>sort(List<T#1>,MyComparable)
T#2 extends Comparable<T#2> declared in method <T#2>compare(T#2,T#2)
1 error
从此错误消息中,似乎编译器无法推断类型参数。是这样的吗?如果是,那为什么会这样呢?
我尝试了各种方式,通过互联网搜索。然后我找到了this JavaCodeGeeks article,它显示了一种方式,所以我尝试了:
sort(list, <T extends Comparable<T>>(a, b) -> a.compareTo(b));
再次不起作用,与该文章声称其有效相反。可能它曾经在一些初始版本中工作。
所以我的问题是:有没有办法为泛型方法创建lambda表达式?我可以通过创建方法使用方法引用来完成此操作:
public static <T extends Comparable<T>> int compare(T obj1, T obj2) {
return obj1.compareTo(obj2);
}
在某些课程中说SO
,并将其传递为:
sort(list, SO::compare);
答案 0 :(得分:101)
如果功能接口中的方法具有类型参数,则不能将 lambda表达式用于功能接口 。见section §15.27.3 in JLS8:
如果 T 是功能接口类型(§9.8)且表达式全等,则lambda表达式与目标类型 T 兼容[..] ,函数类型为[..] T. [..]如果满足以下所有条件,则lambda表达式为全等,并带有函数类型 真:
- 函数类型具有无类型参数。
- [..]
答案 1 :(得分:14)
使用方法引用,我找到了传递参数的其他方法:
List<String> list = Arrays.asList("a", "b", "c");
sort(list, Comparable::<String>compareTo);
答案 2 :(得分:2)
只需编译通用编译器的正确版本即可
(Comparator<String>)
所以答案将是
sort(list, (Comparator<String>)(a, b) -> a.compareTo(b));
答案 3 :(得分:0)
您的意思是这样的吗?:
<T,S>(T t, S s)->...
此lambda是什么类型?您无法在Java中表达这一点,因此无法在函数应用程序中组合此表达式,并且表达式必须是可组合的。
为此,您需要在Java中支持Rank2 Types。
方法被允许是通用的,但是您不能将它们用作表达式。但是,可以在传递它们之前通过专用化所有必需的泛型类型将它们简化为lambda表达式:ClassName::<TypeName>methodName