对 Java 8 比较器类型推断非常困惑
我一直在研究 和 之间的区别,特别是关于使用静态方法以及 lambda 表达式中是否需要参数类型。在我们开始之前,我知道我可以使用方法引用,例如 为了克服我的问题,但我在这里的查询并不是我想要修复的东西,而是我想要的答案,即为什么Java编译器以这种方式处理它。Collections.sort
list.sort
Comparator
Song::getTitle
这些是我的发现。假设我们有一个 类型 ,添加了一些歌曲,有3个标准的获取方法:ArrayList
Song
ArrayList<Song> playlist1 = new ArrayList<Song>();
//add some new Song objects
playlist.addSong( new Song("Only Girl (In The World)", 235, "Rhianna") );
playlist.addSong( new Song("Thinking of Me", 206, "Olly Murs") );
playlist.addSong( new Song("Raise Your Glass", 202,"P!nk") );
以下是对两种有效排序方法的调用,没问题:
Collections.sort(playlist1,
Comparator.comparing(p1 -> p1.getTitle()));
playlist1.sort(
Comparator.comparing(p1 -> p1.getTitle()));
一旦我开始链,就会发生以下情况:thenComparing
Collections.sort(playlist1,
Comparator.comparing(p1 -> p1.getTitle())
.thenComparing(p1 -> p1.getDuration())
.thenComparing(p1 -> p1.getArtist())
);
playlist1.sort(
Comparator.comparing(p1 -> p1.getTitle())
.thenComparing(p1 -> p1.getDuration())
.thenComparing(p1 -> p1.getArtist())
);
即语法错误,因为它不再知道的类型。因此,为了解决这个问题,我将类型添加到第一个参数(比较):p1
Song
Collections.sort(playlist1,
Comparator.comparing((Song p1) -> p1.getTitle())
.thenComparing(p1 -> p1.getDuration())
.thenComparing(p1 -> p1.getArtist())
);
playlist1.sort(
Comparator.comparing((Song p1) -> p1.getTitle())
.thenComparing(p1 -> p1.getDuration())
.thenComparing(p1 -> p1.getArtist())
);
现在来了令人困惑的部分。对于 p,即 List,这解决了以下两个调用的所有编译错误。但是,对于 ,它解决了第一个问题,而不是最后一个问题。我测试添加了几个额外的调用,它总是显示最后一个错误,除非我为参数放置。laylist1.sort
thenComparing
Collections.sort
thenComparing
(Song p1)
现在,我继续通过创建一个和使用:TreeSet
Objects.compare
int x = Objects.compare(t1, t2,
Comparator.comparing((Song p1) -> p1.getTitle())
.thenComparing(p1 -> p1.getDuration())
.thenComparing(p1 -> p1.getArtist())
);
Set<Song> set = new TreeSet<Song>(
Comparator.comparing((Song p1) -> p1.getTitle())
.thenComparing(p1 -> p1.getDuration())
.thenComparing(p1 -> p1.getArtist())
);
与 中发生的情况相同,对于 ,没有编译错误,但对于显示错误的最后一次调用。TreeSet
Objects.compare
thenComparing
任何人都可以解释为什么会发生这种情况,以及为什么在简单地调用比较方法时根本不需要使用(无需进一步调用)。(Song p1)
thenComparing
关于同一主题的另一个查询是当我对:TreeSet
Set<Song> set = new TreeSet<Song>(
Comparator.comparing(p1 -> p1.getTitle())
.thenComparing(p1 -> p1.getDuration())
.thenComparing(p1 -> p1.getArtist())
);
即,从比较方法调用的第一个lambda参数中删除类型,它显示了对比较的调用和第一次调用下的语法错误,但不是对最终调用 - 几乎与上面发生的事情相反!然而,对于所有其他 3 个示例,即 with ,当我删除第一个参数类型时,它会显示所有调用的语法错误。Song
thenComparing
thenComparing
Objects.compare
List.sort
Collections.sort
Song
提前非常感谢。
编辑以包括我在Eclipse Kepler SR2中收到的错误的屏幕截图,我现在发现这些错误是特定于Eclipse的,因为当在命令行上使用JDK8 java编译器编译时,它编译正常。