Java Comparator.reversed() 不使用 lambda 编译

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25172595/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 23:47:23  来源:igfitidea点击:

Comparator.reversed() does not compile using lambda

javalambdajava-8method-reference

提问by Andrey

I have a list with some User objects and i'm trying to sort the list, but only works using method reference, with lambda expression the compiler gives an error:

我有一个包含一些 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

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

采纳答案by Stuart Marks

This is a weakness in the compiler's type inferencing mechanism. In order to infer the type of uin the lambda, the target typefor the lambda needs to be established. This is accomplished as follows. userList.sort()is expecting an argument of type Comparator<User>. In the first line, Comparator.comparing()needs to return Comparator<User>. This implies that Comparator.comparing()needs a Functionthat takes a Userargument. Thus in the lambda on the first line, umust be of type Userand everything works.

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

In the second and third lines, the target typing is disrupted by the presence of the call to reversed(). I'm not entirely sure why; both the receiver and the return type of reversed()are Comparator<T>so it seems like the target type should be propagated back to the receiver, but it isn't. (Like I said, it's a weakness.)

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

In the second line, the method reference provides additional type information that fills this gap. This information is absent from the third line, so the compiler infers uto be Object(the inference fallback of last resort), which fails.

在第二行中,方法引用提供了填补这一空白的附加类型信息。第三行中没有此信息,因此编译器推断uObject(最后的推理回退)失败。

Obviously if you can use a method reference, do that and it'll work. Sometimes you can't use a method reference, e.g., if you want to pass an additional parameter, so you have to use a lambda expression. In that case you'd provide an explicit parameter type in the lambda:

显然,如果您可以使用方法引用,那么就可以使用它。有时你不能使用方法引用,例如,如果你想传递一个额外的参数,那么你必须使用一个 lambda 表达式。在这种情况下,您将在 lambda 中提供显式参数类型:

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

It might be possible for the compiler to be enhanced to cover this case in a future release.

在未来的版本中,可能会增强编译器以涵盖这种情况。

回答by Misha

You can work around this limitation by using the two-argument Comparator.comparingwith Comparator.reverseOrder()as the second argument:

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

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