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

我有一个用户对象的列表,我试图sorting列表,但只能使用方法引用,与lambdaexpression式编译器给出了一个错误:

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 

这是编译器的types推断机制的一个弱点。 为了推断lambda中utypes ,需要build立lambda的目标types 。 这是如下完成的。 userList.sort()期望Comparator<User>types的参数。 在第一行中, Comparator.comparing()需要返回Comparator<User> 。 这意味着Comparator.comparing()需要一个接受User参数的函数。 因此,在第一行的lambda中, u必须是Usertypes的,一切正常。

在第二行和第三行中,目标打字由于存在对reversed()的调用而中断。 我不完全确定为什么; reversed()的接收方和返回types都是Comparator<T>所以看起来目标types应该传回给接收方,但事实并非如此。 (就像我说的,这是一个弱点。)

在第二行中,方法引用提供了填补这个空白的附加types信息。 这个信息在第三行中是不存在的,所以编译器推断uObject (最后一个推论的后备),失败了。

很明显,如果你可以使用方法引用,那么就可以工作。 有时你不能使用方法引用,例如,如果你想传递一个额外的参数,所以你必须使用lambdaexpression式。 在这种情况下,你会在lambda中提供一个显式的参数types:

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

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

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

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