Очень запутанный вывод типа компаратора Java 8

Я смотрел на разницу междуCollections.sort а такжеlist.sortв частности, относительно использованияComparator статические методы и необходимость использования типов параметров в лямбда-выражениях. Прежде чем мы начнем, я знаю, что могу использовать ссылки на методы, например,Song::getTitle чтобы преодолеть мои проблемы, но мой запрос здесь не столько что-то, что я хочу исправить, а что-то, на что я хочу получить ответ, т.е. почему компилятор Java обрабатывает его таким образом.

Это моя находка. Предположим, у нас естьArrayList типаSongс добавлением некоторых песен есть 3 стандартных метода get:

    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())
        );

Теперь здесь прибывает КОНФУЗИОННАЯ часть. Для р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 Тип param показывает синтаксические ошибки для всех вызовов.

Спасибо заранее.

Отредактировано, чтобы включить снимок экрана с ошибками, которые я получал в Eclipse Kepler SR2, которые, как я теперь обнаружил, специфичны для Eclipse, поскольку при компиляции с использованием java-компилятора JDK8 в командной строке он компилируется нормально.

Ответы на вопрос(4)

Ваш ответ на вопрос