Я розглядав різницю між 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 у командному рядку він компілюється в порядку.
