Lambda Expression and generic defined only in method

Suppose I've a generic interface:

interface MyComparable<T extends Comparable<T>>  {
public int compare(T obj1, T obj2);
}

And a method sort:

public static <T extends Comparable<T>>
void sort(List<T> list, MyComparable<T> comp) {
// sort the list
}

I can invoke this method and pass a lambda expression as argument:

List<String> list = Arrays.asList("a", "b", "c");
sort(list, (a, b) -> a.compareTo(b));

That will work fine.

But now if I make the interface non-generic, and the method generic:

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) {
}

And then invoke this like:

List<String> list = Arrays.asList("a", "b", "c");
sort(list, (a, b) -> a.compareTo(b));

It doesn't compile. It shows error at lambda expression saying:

"Target method is generic"

OK, when I compiled it using javac, it shows following error:

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

From this error message, it seems like compiler is not able to infer the type arguments. Is that the case? If yes, then why is it happening like this?

I tried various ways, searched through the internet. Then I found this JavaCodeGeeks article, which shows a way, so I tried:

sort(list, <T extends Comparable<T>>(a, b) -> a.compareTo(b));

which again doesn't work, contrary to what that article claims that it works. Might be possible that it used to work in some initial builds.

So my question is: Is there any way to create lambda expression for a generic method? I can do this using a method reference though, by creating a method:

public static <T extends Comparable<T>> int compare(T obj1, T obj2) {
return obj1.compareTo(obj2);
}

in some class say SO, and pass it as:

sort(list, SO::compare);
86934 次浏览

You can't use a Lambda 表达式 for a 功能界面, if the method in the 功能界面 has type parameters. See 《税务条例》第15.27.3条:

A lambda expression is compatible [..] with a target type T if T is a functional interface type (§9.8) and the expression is congruent with the function type of [..] T. [..] A lambda expression is congruent with a function type if all of the following are 事实:

  • 函数类型为 没有类型参数
  • [..]

使用方法引用,我找到了传递参数的其他方法:

List<String> list = Arrays.asList("a", "b", "c");
sort(list, Comparable::<String>compareTo);

你是说像这样的东西:

<T,S>(T t, S s)->...

这个 Lambda 是什么类型的?在 Java 中无法表达,因此不能在函数应用程序中组合这个表达式,而且表达式必须是可组合的。

为了实现这个需求,您需要在 Java 中支持 排名2类型

方法允许是泛型的,但因此不能将它们用作表达式。但是,在传递它们之前,可以通过专门化所有必要的泛型类型将它们简化为 lambda 表达式: ClassName::<TypeName>methodName

指定编译器的泛型比较器的正确版本 (Comparator<String>)

所以答案是

sort(list, (Comparator<String>)(a, b) -> a.compareTo(b));

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)