Lambda表达式和通用方法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Lambda表达式和通用方法相关的知识,希望对你有一定的参考价值。

假设我有一个通用接口

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表达式处显示错误说:

"目标方法是通用的"

OK,当我用 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);
答案

你不能用 兰姆达表达式 对于 功能界面,如果该方法在 功能界面类型参数. 见 JLS8第15.27.3节。:

一个lambda表达式与目标类型兼容[...]。T 如果 T 是一个功能接口类型(§9.8),表达式是 一致 的函数类型为[...]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表达,因此不能在函数应用中组成这个表达式,表达式必须是可组成的。

要做到这一点,你就需要支持 级别2类型 在Java中,方法是允许通用的,但因此你不能将它们作为表达式使用。

方法是允许通用的,但因此你不能把它们作为表达式使用。然而,通过在传递它们之前对所有必要的通用类型进行特殊化,它们可以被简化为lambda表达式。ClassName::<TypeName>methodName

以上是关于Lambda表达式和通用方法的主要内容,如果未能解决你的问题,请参考以下文章

通用 lambda 及其作为常量表达式的参数

Java Lambda 表达式的官网教程理解

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

Lambda表达式

csharp C#使用Lambda表达式为动态类型和动态属性排序通用列表

EF 通用帮助类 含分页 Lambda 拼接表达式