Нестатический метод не может ссылаться на статический контекст в потоках java 8

Я играл с примерами из http://www.concretepage.com/java/jdk-8/java-8-unaryoperator-binaryoperator-example.

То, что я нахожу очень запутанным, состоит в том, что когда я ошибочно вводил неправильный тип в один из дженериков при создании Collectors, java-компилятор дает мне очень вводящее в заблуждение сообщение:

Нестатический метод не может ссылаться на статический контекст

Моя ошибка не имеет никакого отношения к статическому контексту vs instance:

Map<String, Map<Integer, Integer>> mapOfStudents = list.stream().collect(Collectors.groupingBy(Student::getClassName,
            Collectors.toMap(Student::getName, Student::getAge)));

Моя ошибка в типичном обратном типе. Когда я исправлю его и поставлю:

Map<String, Map<String, Integer>> mapOfStudents

все возвращается к нормальному.

Может кто-нибудь объяснить причину такого запутанного сообщения об ошибке? Я уверен, что он хороший, но я не понимаю его.

EDIT:

~$ java -version
openjdk version "1.8.0_121"
OpenJDK Runtime Environment (build 1.8.0_121-8u121-b13-0ubuntu1.16.04.2-b13)
OpenJDK 64-Bit Server VM (build 25.121-b13, mixed mode)

Ответ 1

Сначала следует отметить, что сообщение выдается не java-компилятором (javac), а IntelliJ IDEA. Вы можете видеть сообщения javac в окне "Построение сообщений" при запуске процесса сборки. То, что вы видите в окне редактора, - это сообщения, созданные самой IDEA, и они могут отличаться.

Сообщение об ошибке вводит в заблуждение из-за реализации эталонного разрешения метода в IntelliJ IDEA. Он считает, что ссылка на нестатические методы должна быть разрешена только в том случае, если число соответствующих аргументов SAM (одиночный абстрактный метод) равно числу аргументов метода плюс один и первый тип аргумента SAM, совместимый с методом, содержащим класс. См. реализация (также метод isSecondSearchPossible выше, для методов varargs выполняется дополнительная магия).

Он работает правильно, если ваша программа не имеет ошибок. Однако, если у вас есть несоответствующий тип, общие аргументы Function, переданные в toMap, не могут быть заменены, поэтому он остается Function<T, R>, а его первый аргумент метода apply - это просто T, который не соответствует тип Student. Таким образом, происходит так называемый "второй поиск", и IDEA считает, что метод ссылается на статический контекст. Хотя статический и нестатический контексты здесь не применимы, нестатический контекст лучше соответствует вашему методу, по крайней мере, в соответствии с количеством аргументов, поскольку метод getName() не получает аргументов. С другой стороны, логика IDEA - "если нестатический контекст не применим, то это статический контекст", следовательно, сообщение об ошибке.

Я рассматривал бы это как ошибку или, по крайней мере, как проблему юзабилити. Я только что зарегистрировал его здесь на основе аналогичного вопроса. Надеюсь, мы это исправим.

Отказ от ответственности: я разработчик IntelliJ IDEA.

Обновление: исправлено в IDEA 2017.2.