Я розглядав різницю між Collections.sort
і list.sort
, зокрема, щодо використання Comparator
статичних методів та того, чи потрібні типи param в лямбда-виразах. Перш ніж ми почнемо, я знаю, що я міг би використовувати посилання на методи, наприклад, Song::getTitle
щоб подолати свої проблеми, але мій запит тут - це не стільки те, що я хочу виправити, скільки те, на що я хочу отримати відповідь, тобто чому компілятор Java обробляє це таким чином .
Це моя знахідка. Припустимо, у нас є ArrayList
тип Song
, з додаванням деяких пісень, існує 3 стандартних методи отримання:
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 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())
);
тобто видалити тип Song
із першого лямбда-параметра для виклику методу порівняння, він показує синтаксичні помилки під викликом порівняння та першого виклику, thenComparing
але не до остаточного виклику thenComparing
- майже протилежне тому, що відбувалося вище! Тоді як для всіх інших 3 прикладів, тобто з Objects.compare
, List.sort
і Collections.sort
коли я видаляю цей перший Song
параметр, він показує синтаксичні помилки для всіх викликів.
Заздалегідь велике спасибі.
Відредаговано, щоб включити знімок екрана помилок, які я отримував у Eclipse Kepler SR2, які, як я зараз виявив, є специфічними для Eclipse, оскільки при компіляції за допомогою компілятора Java JDK8 у командному рядку він компілюється в порядку.