当前位置: 首页 > 知识库问答 >
问题:

Comparator.reversed()不使用lambda编译

乌翰学
2023-03-14

我有一个包含一些用户对象的列表,我正在尝试对列表进行排序,但只使用方法引用,使用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

共有3个答案

阎博易
2023-03-14

与获得赏金的公认的、经过投票的答案相反,这与兰博达斯没有任何关系。

以下汇编:

Comparator<LocalDate> dateComparator = naturalOrder();
Comparator<LocalDate> reverseComparator = dateComparator.reversed();

但以下情况并非如此:

Comparator<LocalDate> reverseComparator = naturalOrder().reversed();

这是因为编译器的类型推断机制不够强大,无法同时执行两个步骤:确定reversed()方法调用需要类型参数LocalDate,因此naturalOrder()方法调用也需要相同的类型参数。

有一种方法可以调用方法并显式传递类型参数。在简单的情况下,它是不必要的,因为它是推断出来的,但是它可以这样做:

Comparator<LocalDate> reverseComparator = Comparator.<LocalDate>naturalOrder().reversed();

在问题中给出的示例中,这将变成:

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

但正如当前接受的答案所示,任何有助于编译器推断方法调用的类型用户,而无需采取额外步骤的操作,因此,在这种情况下,您还可以显式地指定lambda参数的类型,或者使用方法引用User::getName,该引用还包括类型User

陆子石
2023-03-14
匿名用户

您可以通过使用双参数比较器来克服这个限制。将与比较器进行比较。reverseOrder()作为第二个参数:

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

阎咏思
2023-03-14

这是编译器类型推断机制中的一个弱点。为了推断lambda中u的类型,需要建立lambda的目标类型。这是通过以下方式实现的<代码>用户列表。sort()应为Comparator类型的参数

在第二行和第三行中,对reversed()的调用中断了目标键入。我不完全确定为什么;接收器和反向()的返回类型都是比较器

在第二行中,方法引用提供了填补这一空白的其他类型信息。第三行中没有这个信息,所以编译器推断uObject(最后手段的推断回退),这将失败。

显然,如果你能使用一个方法引用,那么这样做就会奏效。有时不能使用方法引用,例如,如果要传递附加参数,则必须使用lambda表达式。在这种情况下,需要在lambda中提供一个显式参数类型:

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

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

 类似资料:
  • 问题内容: 我有一个包含一些User对象的列表,我正在尝试对列表进行排序,但是只能使用方法引用来工作,对于lambda表达式,编译器会给出错误: 错误: 问题答案: 这是编译器的类型推断机制的一个弱点。为了推断ulambda的类型,需要建立lambda的目标类型。这是如下完成的。期待类型为的参数。在第一行中,需要返回。这意味着需要一个带参数的a 。因此,在第一行的中,必须为并且一切正常。 在第二行

  • 问题内容: 我有以下代码: 当我通过main方法运行它时,它运行良好,但是当我尝试对其进行编译时,抛出以下错误: 我正在使用Eclipse IDE,并尝试通过命令行进行编译。 问题答案: 默认情况下,使用Java 5来编译类。引用其文档: 还要注意,当前的默认源设置是1.5,默认目标设置是1.5,与运行Maven的JDK无关。如果要更改这些默认值,则应按照设置Java编译器的- source和-t

  • 我试图用TBB和lambda表达式编写一个基本的C程序,但我无法编译它<代码> 和编译器消息: 我尝试了编译器标志"-std=c 11"和"-std=gnu 11",然后输出: 我使用的是Fedora18(当然安装了tbb和tbb-devel软件包)。 有人有什么想法吗?代码从此处复制:http://software.intel.com/en-us/blogs/2009/08/03/paralle

  • 此代码编译没有任何问题Qt5.2.0 MSVC2012: 但是如果我试着用Qt5编译它。2.0使用gcc时,我遇到以下错误: ../_测试夹具B/主。cpp:在函数“int main(int,char**)”中:/_测试夹具B/主。cpp:14:5:警告:lambda表达式仅适用于-std=c 11或-std=gnu 11[默认情况下启用]});^/_测试夹具B/主。cpp:14:6:错误:调用'

  • 对于Java 8,我有以下代码: 我想转换成lambda风格, 使用像这样的< code>ifExist方法: 但现在我还有其他案例可以调用: 我可以写一个类似的< code>ifNotExist,我希望它们是互斥的(如果< code>Exist条件为真,就不需要检查< code>ifNotExist,因为有时候,exist()方法检查起来工作量太大),但是我总是要检查两次。我该如何避免呢? 也许

  • 我正在使用NetBeans 8。当我的代码包含Lambda表达式并尝试编译时,我会收到以下错误消息: