Lambda 表达式和仅在方法中定义的泛型

2022-08-31 09:06:38

假设我有一个通用接口:

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);

答案 1

如果函数接口中的方法具有类型参数,则不能对函数接口使用 lambda 表达式。请参阅 JLS8 中的 §15.27.3 节

如果 Lambda 表达式是函数接口类型 (§9.8),并且表达式与 [..] T. [..] 的函数类型一致,则 lambda 表达式与目标类型 T 兼容。如果满足以下所有条件,则 lambda 表达式与函数类型一

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

答案 2

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

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

推荐