我有一个包含一些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
这是编译器的类型推断机制的一个弱点。为了推断ulambda的类型,需要建立lambda的目标类型。这是如下完成的。userList.sort()期待类型为的参数Comparator<User>。在第一行中,Comparator.comparing()需要返回Comparator<User>。这意味着Comparator.comparing()需要一个Function带User参数的a 。因此,在第一行的lambda中,u必须为type User并且一切正常。
userList.sort()
Comparator<User>
Comparator.comparing()
Function
User
lambda
u
type User
在第二行和第三行中,对的调用会干扰目标类型reversed()。我不完全清楚为什么。接收器和的返回类型reversed()都是Comparator<T>如此,因此似乎应该将目标类型传播回接收器,但事实并非如此。(就像我说的那样,这是一个缺点。)
reversed()
Comparator<T>
在第二行中,方法参考提供了填补此空白的其他类型信息。第三行缺少此信息,因此编译器推断u为Object(失败的推断回退),这将失败。
Object
显然,如果可以使用方法引用,则可以使用它。有时你不能使用方法引用,例如,如果你想传递附加参数,则必须使用lambda表达式。在这种情况下,你可以在lambda中提供一个明确的参数类型:
userList.sort(Comparator.comparing((User u) -> u.getName()).reversed());
在将来的发行版中,可能会增强编译器以涵盖这种情况。