Przyglądałem się różnicy między Collections.sort
i list.sort
, w szczególności w odniesieniu do używania Comparator
metod statycznych i tego, czy typy parametrów są wymagane w wyrażeniach lambda. Zanim zaczniemy, wiem, że mógłbym użyć referencji do metod, np. Song::getTitle
Aby przezwyciężyć swoje problemy, ale moje zapytanie tutaj nie jest czymś, co chcę naprawić, ale czymś, na co chcę odpowiedzi, tj. Dlaczego kompilator Java obsługuje to w ten sposób .
Oto moje odkrycie. Załóżmy, że mamy ArrayList
typ Song
, z dodanymi utworami, istnieją 3 standardowe metody pobierania:
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") );
Oto wywołanie obu typów metod sortowania, które działają, nie ma problemu:
Collections.sort(playlist1,
Comparator.comparing(p1 -> p1.getTitle()));
playlist1.sort(
Comparator.comparing(p1 -> p1.getTitle()));
Gdy tylko zacznę łączyć thenComparing
, dzieje się co następuje:
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())
);
tj. błędy składniowe, ponieważ nie zna już typu p1
. Aby to naprawić, dodaję typ Song
do pierwszego parametru (porównania):
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())
);
Teraz czas na część Mylące. Dla p laylist1.sort
, czyli Listy, rozwiązuje to wszystkie błędy kompilacji dla obu poniższych thenComparing
wywołań. Jednak Collections.sort
rozwiązuje to dla pierwszego, ale nie ostatniego. Testowałem dodałem kilka dodatkowych wywołań do thenComparing
i zawsze pokazuje błąd dla ostatniego, chyba że wstawię (Song p1)
parametr.
Teraz poszedłem dalej przetestować to, tworząc TreeSet
i używając 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())
);
To samo dzieje się w przypadku TreeSet
, nie ma błędów kompilacji, ale Objects.compare
ostatnie wywołanie thenComparing
pokazuje błąd.
Czy ktoś może wyjaśnić, dlaczego tak się dzieje, a także dlaczego w ogóle nie ma potrzeby używania, (Song p1)
gdy po prostu wywołuje metodę porównywania (bez dalszych thenComparing
wywołań).
Jeszcze jedno zapytanie na ten sam temat dotyczy tego TreeSet
:
Set<Song> set = new TreeSet<Song>(
Comparator.comparing(p1 -> p1.getTitle())
.thenComparing(p1 -> p1.getDuration())
.thenComparing(p1 -> p1.getArtist())
);
tzn. usuń typ Song
z pierwszego parametru lambda dla wywołania metody porównującej, pokaże błędy składniowe pod wywołaniem porównania i pierwsze wywołanie, thenComparing
ale nie ostatnie wywołanie thenComparing
- prawie odwrotność tego, co działo się powyżej! Podczas gdy dla wszystkich pozostałych 3 przykładów, tj. Z Objects.compare
, List.sort
i Collections.sort
kiedy usuwam ten pierwszy Song
typ parametru, pokazuje on błędy składniowe dla wszystkich wywołań.
Z góry bardzo dziękuję.
Edytowano tak, aby zawierał zrzut ekranu błędów, które otrzymałem w Eclipse Kepler SR2, które teraz znalazłem, są specyficzne dla Eclipse, ponieważ po skompilowaniu za pomocą kompilatora JDK8 java w wierszu poleceń kompiluje się OK.