Sehr verwirrt von Java 8 Comparator-Typinferenz
Ich habe den Unterschied zwischen untersuchtCollections.sort
undlist.sort
, speziell in Bezug auf die Verwendung derComparator
statische Methoden und ob Parametertypen in den Lambda-Ausdrücken erforderlich sind. Bevor wir anfangen, weiß ich, dass ich Methodenreferenzen verwenden könnte, z.Song::getTitle
um meine Probleme zu überwinden, aber meine Abfrage hier ist nicht so sehr etwas, das ich beheben möchte, sondern etwas, auf das ich eine Antwort haben möchte, d. h. warum behandelt der Java-Compiler dies auf diese Weise.
Das sind meine Erkenntnisse. Angenommen, wir haben eineArrayList
vom TypSong
Mit einigen hinzugefügten Songs gibt es 3 Standard-Get-Methoden:
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") );
Hier ist ein Aufruf für beide Arten von Sortiermethoden, der problemlos funktioniert:
Collections.sort(playlist1,
Comparator.comparing(p1 -> p1.getTitle()));
playlist1.sort(
Comparator.comparing(p1 -> p1.getTitle()));
Sobald ich anfange zu kettenthenComparing
passiert folgendes:
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())
);
d.h. Syntaxfehler, da der Typ von nicht bekannt istp1
nicht mehr. Um dies zu beheben, füge ich den Typ hinzuSong
zum ersten Parameter (zum Vergleichen):
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())
);
Jetzt kommt hier der verwirrende Teil. Für Playlist1.sort
d.h. die Liste, dies löst alle Kompilierungsfehler für beide folgendenthenComparing
Anrufe. FürCollections.sort
, es löst es für den ersten, aber nicht den letzten. Ich habe getestet, mehrere zusätzliche Anrufe hinzugefügtthenComparing
und es zeigt immer einen Fehler für den letzten, es sei denn, ich setze(Song p1)
für den Parameter.
Nun teste ich dies weiter mit dem Erstellen einesTreeSet
und mitObjects.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())
);
Das gleiche passiert wie inTreeSet
, es gibt keine übersetzungsfehler aber fürObjects.compare
der letzte anruf anthenComparing
zeigt einen Fehler.
Kann jemand bitte erklären, warum dies geschieht und warum es nicht erforderlich ist, es zu verwenden(Song p1)
überhaupt beim einfachen Aufrufen der Vergleichsmethode (ohne weiterethenComparing
Anrufe).
Eine andere Frage zum selben Thema ist, wann ich das macheTreeSet
:
Set<Song> set = new TreeSet<Song>(
Comparator.comparing(p1 -> p1.getTitle())
.thenComparing(p1 -> p1.getDuration())
.thenComparing(p1 -> p1.getArtist())
);
d.h. den Typ entfernenSong
Ab dem ersten Lambda-Parameter für den Aufruf der Vergleichsmethode werden Syntaxfehler unter dem Aufruf zum Vergleichen und dem ersten Aufruf von angezeigtthenComparing
aber nicht zum abschließenden aufruf anthenComparing
- fast das Gegenteil von dem, was oben geschah! Während für alle anderen 3 Beispiele, d.h.Objects.compare
, List.sort
undCollections.sort
wenn ich das zuerst entferneSong
Param-Typ zeigt Syntaxfehler für alle Aufrufe.
Vielen Dank im Voraus.
Bearbeitet, um einen Screenshot der Fehler aufzunehmen, die ich in Eclipse Kepler SR2 erhalten habe, die ich nun gefunden habe. Sie sind Eclipse-spezifisch, da sie beim Kompilieren mit dem Java-Compiler JDK8 in der Befehlszeile OK kompilieren.