假设我有一个通用接口:
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
从这个错误消息来看,编译器似乎无法推断类型参数。是这样吗?如果是的话,为什么会出现这样的情况?
我尝试了各种方法,通过互联网搜索。然后我发现了这篇JavaCodeGeeks文章,它展示了一种方法,所以我尝试了:
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);
如果功能接口中的方法具有类型参数,则不能将lambda表达式用于功能接口。请参阅 JLS8 中的第 §15.27.3 节:
如果 T 是函数接口类型(第 9.8 节)并且表达式与 [..] T.[ 的函数类型一致,则 lambda 表达式与目标类型 T 兼容 [..]。 .] 如果满足以下所有条件,则 lambda 表达式与函数类型全等 正确:
- 函数类型有 没有类型参数。
- [..]
使用方法引用,我找到了其他方法来传递参数:
List<String> list = Arrays.asList("a", "b", "c");
sort(list, Comparable::<String>compareTo);
只需将编译器指向通用比较器的正确版本即可
(Comparator<String>)
所以答案是
sort(list, (Comparator<String>)(a, b) -> a.compareTo(b));
你的意思是这样的吗?:
<T,S>(T t, S s)->...
这个 lambda 是什么类型?您无法在 Java 中表达这一点,因此无法在函数应用程序中编写此表达式,并且表达式必须是可组合的。
为了完成这项工作,您需要 Java 中对 Rank2 Types 的支持。
方法允许是通用的,但因此不能将它们用作表达式。然而,在传递它们之前,可以通过专门化所有必要的泛型类型来将它们简化为 lambda 表达式:
ClassName::<TypeName>methodName
List<String> list = Arrays.asList("a", "b", "c");
sort(list, Comparable::<String>compareTo);
int compareTo (T o)
不是通用方法调用。虽然 Comparable<T>
是一个带有类型的接口。即使 compareTo
返回了 T
,即 T compareTo (T o)
,它仍然不是通用方法。为了使其成为通用方法,它需要包含 type parameters
列表,即 <T> T compareTo (T o)
。
lambda 表达式无法声明类型参数,因此它不能具有抽象方法为泛型的目标类型。 在这种情况下,你需要使用方法参考