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

问题描述 投票:0回答:6

假设我有一个通用接口:

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);
java generics lambda java-8
6个回答
136
投票

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

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

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

21
投票

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

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

5
投票

只需将编译器指向通用比较器的正确版本即可

(Comparator<String>)

所以答案是

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


0
投票

你的意思是这样的吗?:

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

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

为了完成这项工作,您需要 Java 中对 Rank2 Types 的支持。

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

ClassName::<TypeName>methodName


0
投票
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)


0
投票

lambda 表达式无法声明类型参数,因此它不能具有抽象方法为泛型的目标类型。 在这种情况下,你需要使用方法参考

© www.soinside.com 2019 - 2024. All rights reserved.