Sehr verwirrt von Java 8 Komparator-Typ-Inferenz
Habe ich den Unterschied zwischen Collections.sort
und list.sort
, insbesondere in Bezug auf die Verwendung der Comparator
statische Methoden und ob param Typen erforderlich sind in der lambda-Ausdrücke. Bevor wir beginnen, ich weiß, dass ich verwenden könnte, Methode, Referenzen, z.B. Song::getTitle
zu überwinden, meine Probleme, aber meine Anfrage hier ist nicht so sehr etwas, was ich beheben wollen, sondern etwas, was ich wollen eine Antwort, also warum ist der Java-compiler die Handhabung es auf diese Weise.
Diese sind bei meinem Befund. Nehmen wir an, wir haben eine ArrayList
Typ Song
mit einigen songs Hinzugefügt, es gibt 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 an beide Typen der sort-Methode, die funktioniert, kein problem:
Collections.sort(playlist1,
Comparator.comparing(p1 -> p1.getTitle()));
playlist1.sort(
Comparator.comparing(p1 -> p1.getTitle()));
Sobald ich an die Kette thenComparing
ist, geschieht 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. syntax-Fehler, weil Sie nicht wissen, die Art der p1
mehr. So, dies zu beheben, ich geben Sie Song
auf den ersten parameter (der Vergleich):
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 der VERWIRRENDE Teil. Für playlist1.sort
, D. H. die Liste, diese lösen alle Kompilierungsfehler, für die beiden folgenden thenComparing
Anrufe. Jedoch, für Collections.sort
, es löst es für das erste, aber nicht der Letzte. Getestet habe ich Hinzugefügt einige zusätzliche Aufrufe thenComparing
und es zeigt immer einen Fehler an, für den letzten, wenn ich (Song p1)
für die parameter.
Nun ging ich auf um zu testen, dies weiter mit der Erstellung eines TreeSet
und mit 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())
);
Das gleiche passiert wie in, für die TreeSet
gibt es keine Kompilierungsfehler aber für Objects.compare
dem letzten Aufruf thenComparing
erscheint eine Fehlermeldung.
Kann mir jemand bitte erklären, warum das passiert ist und auch warum gibt es keine Notwendigkeit zu verwenden (Song p1)
an alle, wenn Sie einfach den Aufruf der Vergleichs-Methode (ohne weitere thenComparing
Anrufe).
Einer anderen Abfrage auf das gleiche Thema ist, wenn ich dies tun, um die TreeSet
:
Set<Song> set = new TreeSet<Song>(
Comparator.comparing(p1 -> p1.getTitle())
.thenComparing(p1 -> p1.getDuration())
.thenComparing(p1 -> p1.getArtist())
);
D. H. entfernen der Typ Song
von der ersten lambda-parameter für die Vergleich-Methode aufrufen, zeigt es syntax-Fehler unter den Aufruf zu vergleichen und den ersten Anruf zu thenComparing
aber nicht der Letzte Aufruf thenComparing
- fast das Gegenteil von dem, was passiert war oben! In der Erwägung, dass, für alle anderen 3 Beispiele, d.h. mit Objects.compare
, List.sort
und Collections.sort
wenn ich die zuerst entfernen Song
param-Typ zeigt es syntax-Fehler für alle Anrufe.
Vielen Dank im Voraus.
Bearbeitet gehören screenshot von Fehler, die ich erhalte in Eclipse Kepler SR2, die ich jetzt haben, da sind Eclipse-spezifisch, weil bei der Kompilierung mit dem JDK8 java-compiler auf der Kommandozeile kompiliert OK.
um ehrlich zu sein, ich denke, es wäre das einfachste für jemanden, um zu sehen, was die Probleme sind, durch ausführen der source code selbst.
Was sind die Arten von
t1
und t2
im Objects.compare
Beispiel? Ich versuche zu folgern, aber die Schichtung mein Typ-Inferenz über der compiler die Typ-Inferenz ist unlösbar. 🙂Auch welche compiler verwenden Sie?
Sie haben zwei getrennte Probleme hier. Einer der Beantworter darauf hingewiesen, Sie könnte verwenden Sie die Methode verweist, die Sie sorta abgebürstet. Genauso wie Lambda-Ausdrücke kommen in beiden "explizit typisierte" und "implizit typisierte" Aromen, Methode, Referenzen kommen in "exakt" sind (überlastung) und "ungenau" (mehrere überladungen) Aromen. Entweder eine genaue Methode ref oder ein expliziter lambda-Ausdruck kann verwendet werden, um zusätzliche Eingabe von Informationen, wenn Sie nicht vorhanden ist. (Explizite Typ-Zeugen und Besetzungen können auch verwendet werden, aber sind oft größer Hämmer.)
InformationsquelleAutor Tranquility | 2014-06-26
Du musst angemeldet sein, um einen Kommentar abzugeben.
Erste, alle die Beispiele, die Sie sagen, die Fehler verursachen kompilieren problemlos mit der Referenz-Implementierung (javac aus dem JDK 8.) Sie auch feine arbeiten im IntelliJ, so seine durchaus möglich, die Fehler, die Sie sehen, sind Eclipse-spezifisch.
Ihre zugrunde liegende Frage scheint zu sein: "warum muss es aufhören zu arbeiten, wenn ich starten Verkettung." Der Grund dafür ist, während die lambda-Ausdrücke und generische Methodenaufrufe sind poly Ausdrücke (Ihre Art ist Kontext-Sensitiv), wenn Sie als Parameter der Methode, wenn Sie erscheinen stattdessen als Methode-Empfänger Ausdrücken, sind Sie nicht.
Wenn Sie sagen,
gibt es genug information in der Art zu lösen, sowohl für den Typ-argument von
comparing()
und der argument-Typp1
. Diecomparing()
Anruf bekommt seine Ziel-Typ in der Signatur vonCollections.sort
, so ist es bekanntcomparing()
muss wieder einComparator<Song>
, und daherp1
mussSong
.Aber wenn Sie anfangen, Verkettung:
jetzt haben wir ein problem. Wir wissen, dass der zusammengesetzte Ausdruck
comparing(...).thenComparing(...)
hat ein Ziel Art derComparator<Song>
, aber da der receiver Ausdruck für die Kettecomparing(p -> p.getTitle())
ist eine generische Methode aufrufen, und die können wir nicht ableiten, Ihre Typ-Parameter aus seinen anderen Argumenten, sind wir irgendwie Pech. Da wir nicht wissen, die Art dieses Ausdrucks, wissen wir nicht, dass es einethenComparing
- Methode, etc.Gibt es mehrere Möglichkeiten, um dieses Problem zu lösen, von denen alle beinhalten die Injektion mehr Informationen geben, so dass das erste Objekt in der Kette kann richtig eingegeben haben. Hier sind Sie, in groben Reihenfolge der abnehmenden Attraktivität und zunehmende Aufdringlichkeit:
Song::getTitle
. Dies ergibt dann genug Typ-Informationen, um Rückschlüsse auf die Art der Variablen für diecomparing()
nennen, und daher gebe es ein Typ, und daher weiter unten in der Kette.comparing()
nennen:Comparator.<Song, String>comparing(...)
.Comparator<Song>
.Danke für deine Antwort, Brian. Allerdings, finde ich immer noch etwas unbeantwortet bleibt, warum nicht Liste.Sortieren Sie sich anders Verhalten, Sammlungen.Art, dass der ehemalige erfordert nur die erste lambda-Ausdruck enthalten, der parameter-Typ, aber das letztere erfordert auch die letzten auf, wenn ich z.B. ein Vergleich gefolgt von 5 thenComparing Anrufe, ich hätte zu setzen (Lied p1) im Vergleich und in der letzten thenComparing. Auch in meinem ursprünglichen post sehen Sie unten Beispiel TreeSet, wo ich entfernen Sie alle param-Typen und noch der Letzte Aufruf thenComparing ist OK aber der andere nicht - so verhält sich diese anders.
Sind Sie immer noch mit der Eclipse-compiler? Ich habe nicht gesehen, dieses Verhalten auch, wenn ich verstehe deine Frage richtig. Können Sie (a) versuchen Sie es mit javac aus dem JDK 8 und (b) wenn es immer noch nicht, poste den code?
Vielen Dank für diese Anregung. Ich habe gerade zusammengestellt, es in das Kommando-Fenster mit javac und kompiliert, wie Sie sagte. Es scheint sich um ein Eclipse-Problem. Ich habe noch nicht aktualisiert auf Eclipse Luna, was ist Zweck-gebaut für JDK8 also hoffentlich kann es behoben werden dass. Ich habe eigentlich einen screenshot um dir zu zeigen was geschehen war, in Eclipse aber nicht wissen, wie die post hier.
Ich denke du meinst
Comparator.<Song, String>comparing(...)
.InformationsquelleAutor Brian Goetz
Das problem ist, geben Leitlinien. Ohne eine
(Song s)
zu den ersten Vergleichcomparator.comparing
weiß nicht, den Typ der Eingabe, so wird standardmäßig Objekt.Können Sie dieses Problem beheben problem 1 von 3 Möglichkeiten:
Nutzung der neuen Java-8-Methode Referenz-syntax
Ziehen Sie aus jedem Vergleich Schritt in eine lokale Referenz
BEARBEITEN
Zwingen, die Art zurückgegeben, die durch den Komparator (Hinweis: Sie müssen sowohl die Art des Eingangs und der Vergleich key-Typ)
Ich denke, die "letzten"
thenComparing
syntax Fehlermeldung ist irreführend, Sie. Es ist eigentlich eine Art problem mit der ganzen Kette, es ist nur der compiler nur markiert das Ende der Kette wie eine syntax-Fehler, weil das ist, wenn die endgültige Rückkehr Typ passt nicht, denke ich.Ich bin mir nicht sicher, warum
List
ist, macht einen besseren job Leitlinien alsCollection
da sollte es das gleiche tun, capture-Typ, aber offensichtlich nicht.ArrayList
aber nicht für dieCollections
Lösung (gegeben wird der erste Anruf in der Kette hat eineSong
parameter)?Danke für Eure Antworten, aber wenn du meinen post gelesen würden Sie sehen, sagte ich: "Bevor wir beginnen, ich weiß, dass ich verwenden könnte, Methode, Referenzen, z.B. Song::getTitle zu überwinden, meine Probleme, aber meine Anfrage hier ist nicht so sehr etwas, was ich beheben wollen, sondern etwas, was ich wollen eine Antwort, also warum ist der Java-compiler die Handhabung es auf diese Weise."
Ich will eine Antwort auf die Frage, warum der compiler verhält sich auch so, wenn ich die Verwendung von lambda-Ausdrücken. Es akzeptiert den Vergleich(s -> en.getArtist()) aber wenn ich dann auf die Kette .thenComparing(s -> en.getDuration()) zum Beispiel es gibt mir Fehler in der syntax bei beiden aufrufen, wenn ich dann hinzufügen eines expliziten Typs im Vergleich nennen, z.B. Vergleich von((s Song) -> en.getArtist ()), dann ist dies behebt das problem und für die Liste.TreeSet Sortieren und es löst sich auch alle weiteren Zusammenstellung von Fehlern, ohne dass zusätzliche param-Typen, jedoch für die Sammlungen.Art & Objekte.vergleichen Sie in die Beispiele der letzten thenComparing immer noch nicht
InformationsquelleAutor dkatzel
playlist1.sort(...)
schafft eine Schranke der Song für den Typ der variable E, aus der Erklärung der playlist1, die "Wellen" an den Komparator.In
Collections.sort(...)
gibt es keine solche Grenze, und der Rückschluss von der Art des dem ersten Komparator ist nicht genug für den compiler zu folgern den rest.Ich denke, Sie würden Holen Sie sich "korrekt" Verhalten von
Collections.<Song>sort(...)
, aber nicht über ein java 8 zu installieren um es zu testen für Sie.InformationsquelleAutor amalloy
Anderen Weg, um mit dieser compile-Zeit-Fehler:
Werfen Sie Ihre ersten Vergleich-Funktion die variable explizit und dann gut zu gehen. Ich habe die Sortierung der Liste der org.bson.Dokumenten-Objekt. Bitte schauen Sie auf Beispiel-code
InformationsquelleAutor Rajni Gangwar