3 回答
TA贡献1805条经验 获得超10个赞
首先,您说的所有示例均会导致错误使用参考实现(来自JDK 8的javac)进行编译。它们在IntelliJ中也能正常运行,因此您看到的错误很可能是特定于Eclipse的。
您的基本问题似乎是:“为什么当我开始链接时它会停止工作。” 原因是,当lambda表达式和通用方法调用作为方法参数出现时是多义表达式(它们的类型是上下文相关的),而当它们作为方法接收者表达式出现时却不是。
当你说
Collections.sort(playlist1, comparing(p1 -> p1.getTitle()));
有足够的类型信息可以解决的类型参数comparing()和参数类型p1。该comparing()调用从的签名获取其目标类型Collections.sort,因此已知该调用comparing()必须返回Comparator<Song>,因此p1必须为Song。
但是,当您开始链接时:
Collections.sort(playlist1,
comparing(p1 -> p1.getTitle())
.thenComparing(p1 -> p1.getDuration())
.thenComparing(p1 -> p1.getArtist()));
现在我们有一个问题。我们知道复合表达式comparing(...).thenComparing(...)的目标类型为Comparator<Song>,但是由于链的接收方表达式comparing(p -> p.getTitle())是通用方法调用,并且我们无法从其他参数推断其类型参数,因此我们有点不走运。由于我们不知道此表达式的类型,因此我们不知道它具有thenComparing方法,等等。
有几种方法可以解决此问题,所有方法都涉及注入更多类型信息,以便可以正确键入链中的初始对象。在这里,它们按照减少期望和增加干扰的大致顺序排列:
使用精确的方法引用(没有重载的方法引用),例如Song::getTitle。然后,这会提供足够的类型信息以推断出该comparing()调用的类型变量,从而为其提供类型,并因此继续进行下去。
使用显式lambda(如您在示例中所做的那样)。
提供comparing()呼叫的见证人:Comparator.<Song, String>comparing(...)。
通过将接收者表达式强制转换为,为显式目标类型提供强制类型转换Comparator<Song>。
TA贡献1804条经验 获得超8个赞
playlist1.sort(...) 从播放列表1的声明为类型变量E创建Song的界限,该声明“波纹”到比较器。
在中Collections.sort(...),没有这样的界限,并且从第一个比较器的类型进行的推断不足以使编译器推断出其余的。
我认为您会从中获得“正确”的行为Collections.<Song>sort(...),但是没有安装Java 8可以为您进行测试。
添加回答
举报