Lambda表达式和通用方法

时间:2014-03-23 08:18:00

标签: java generics lambda java-8

假设我有一个通用接口:

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

4 个答案:

答案 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