Я изучал разницу между Collections.sortи list.sort, особенно в отношении использования Comparatorстатических методов и того, требуются ли типы параметров в лямбда-выражениях. Прежде чем мы начнем, я знаю, что могу использовать ссылки на методы, например, 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- почти полная противоположность тому, что происходило выше! Принимая во внимание, что для всех остальных трех примеров, то есть с Objects.compare, List.sortи Collections.sortкогда я удаляю это первымSong тип паров он показывает ошибки синтаксиса для всех вызовов.
Спасибо заранее.
Отредактировано, чтобы включить снимок экрана с ошибками, которые я получал в Eclipse Kepler SR2, которые, как я обнаружил, специфичны для Eclipse, потому что при компиляции с использованием java-компилятора JDK8 в командной строке он компилируется нормально.
