代码之家  ›  专栏  ›  技术社区  ›  Rohit Jain

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

  •  121
  • Rohit Jain  · 技术社区  · 10 年前

    假设我有一个通用接口:

    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=数组.asList(“a”、“b”、“c”);
    排序(列表,(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);
    
    5 回复  |  直到 3 年前
        1
  •  134
  •   Rohit Jain    10 年前

    您不能使用 lambda表达式 对于 功能接口 ,如果 功能接口 类型参数 看见 section §15.27.3 in JLS8 :

    lambda表达式与目标类型兼容[..] T 如果 T 是函数接口类型(§9.8),表达式为 一致的 函数类型为[..]T.[..]lambda表达式为 一致的 如果以下所有情况都是 真:

    • 函数类型具有 无类型参数 .
    • [..]
        2
  •  21
  •   Andrey    10 年前

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

    List<String> list = Arrays.asList("a", "b", "c");        
    sort(list, Comparable::<String>compareTo);
    
        3
  •  4
  •   Aleч    6 年前

    只需使用 (Comparator<String>)

    所以答案是

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

        4
  •  0
  •   iconfly    6 年前

    你的意思是这样吗

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

    这个lambda是什么类型的?您无法在Java中表达这一点,因此无法在函数应用程序中组合此表达式,表达式必须是可组合的。

    对于这项工作,您需要支持 Rank2 Types 在Java中。

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

        5
  •  0
  •   Sanjay    3 年前
    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) .