Comparator.reversed()不使用lambda进行编译


111

我有一个包含一些User对象的列表,我正在尝试对列表进行排序,但是只能使用方法引用来工作,对于lambda表达式,编译器会给出错误:

List<User> userList = Arrays.asList(u1, u2, u3);
userList.sort(Comparator.comparing(u -> u.getName())); // works
userList.sort(Comparator.comparing(User::getName).reversed()); // works
userList.sort(Comparator.comparing(u -> u.getName()).reversed()); // Compiler error

错误:

com\java8\collectionapi\CollectionTest.java:35: error: cannot find symbol
            userList.sort(Comparator.comparing(u -> u.getName()).reversed());
                                                     ^
symbol:   method getName()
location: variable u of type Object
1 error

Answers:


145

这是编译器的类型推断机制的一个弱点。为了推断ulambda的类型,需要建立lambda的目标类型。如下完成。userList.sort()期待类型为的参数Comparator<User>。在第一行中,Comparator.comparing()需要返回Comparator<User>。这意味着Comparator.comparing()需要一个FunctionUser参数的a 。因此,在第一行的lambda中,u必须为type User并且一切正常。

在第二行和第三行中,对的调用会中断目标类型reversed()。我不完全确定为什么;接收器和的返回类型reversed()都是Comparator<T>如此,因此似乎应该将目标类型传播回接收器,但事实并非如此。(就像我说的那样,这是一个缺点。)

在第二行中,方法参考提供了填补此空白的其他类型信息。第三行缺少此信息,因此编译器将推断uObject(失败的推断回退),这将失败。

显然,如果可以使用方法引用,则可以使用它。有时您不能使用方法引用,例如,如果您想传递附加参数,则必须使用lambda表达式。在这种情况下,您可以在lambda中提供一个明确的参数类型:

userList.sort(Comparator.comparing((User u) -> u.getName()).reversed());

将来的发行版中可能会增强编译器以涵盖这种情况。


28
Lambda分为隐式类型(无参数的清单类型)和显式类型;方法引用分为精确(无重载)和不精确。当接收方位置的泛型方法调用具有lambda参数,并且无法从其他参数完全推断出类型参数时,您需要提供显式lambda,精确方法引用,目标类型强制转换或显式类型见证通用方法调用,以提供继续进行所需的其他类型信息。
Brian Goetz 2014年

1
@StuartMarks,您“并不完全确定为什么”编译器是这样工作的。但是语言规范怎么说?根据语言规范,是否应该有足够的信息来确定泛型类型?如果是这样,这是一个编译器错误,应予以归档并进行相应处理。否则,这是应该改进Java语言的领域。哪有
加勒特·威尔逊

8
我认为我们可以将Brian的评论视为权威性的,因为他撰写了有问题的规范:-)
minimalis

1
可悲的是,没有一个可以解释为什么它不能反向运行而不能反向运行。
Chris311,19年

90

您可以通过使用两个参数Comparator.comparingwith Comparator.reverseOrder()作为第二个参数来解决此限制:

users.sort(comparing(User::getName, reverseOrder()));

4
真好 我比使用显式类型的lambda更好。或者,更好的是users.sort(reverseOrder(comparing(User::getName)));
2015年

10
请注意,上述reverseOrder(Comparator<T>)方法位于中java.util.Collections,而不位于中Comparator
2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.