Статический контекст не может получить доступ к нестатическому в коллекторах

У меня есть группа студентов. Сначала я хочу сгруппировать их по меткам. Затем я хочу еще больше сгруппировать эти наборы в студентов с одинаковыми именами.

Map<Integer,Map<String,List<String>>> groupping = students.stream()
                                                    .collect(Collectors.groupingBy(Student::getMarks, 
                                                            Collectors.mapping(Student::getName,Collectors.toList())));

Я получаю сообщение об ошибке,

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

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

Вместо того, как это исправить; Я действительно хочу знать, что здесь происходит. Любой ваш вклад приветствуется!

Потому что если я напишу, что приведенная ниже группировка полностью действительна;

Map<Integer,List<Student>> m = students.stream().
        collect(Collectors.groupingBy(Student::getMarks));

Вот мой класс Student.java (если вам это нужно)

public class Student {
    private String name;
    private int marks;
    // getters, setters, constructor and toString
}

person Jude Niroshan    schedule 21.10.2016    source источник
comment
что вы пытаетесь хранить внутри Map‹String,List‹String›› ?? Я имею в виду, что такое объект String, который вы собираетесь хранить внутри List‹String›?? Список учеников??   -  person Supun Wijerathne    schedule 23.10.2016
comment
@SupunWijerathne На самом деле, я собирался хранить Student в самом внутреннем List.   -  person Jude Niroshan    schedule 23.10.2016
comment
Так что это должен быть список «Студент». не так ли? :))   -  person Supun Wijerathne    schedule 23.10.2016


Ответы (2)


К сожалению, появляется сообщение об ошибке «На нестатический метод нельзя ссылаться из статического контекста». является просто заполнителем для любой проблемы несоответствия типов, когда задействованы ссылки на методы. Компилятор просто не смог определить реальную проблему.

В вашем коде целевой тип Map<Integer, Map<String, List<String>>> не соответствует типу результата комбинированного сборщика, который равен Map<Integer, List<String>>, но компилятор не пытался определить этот (автономный) тип результата, так как (вложенные) общие вызовы методов, включающие для ссылок на методы требуется целевой тип для разрешения ссылок на методы. Таким образом, он сообщает не о несоответствии типа присваивания, а о проблеме с разрешением ссылок на методы.

Правильный код просто

Map<Integer, List<String>> groupping = students.stream()
    .collect(Collectors.groupingBy(Student::getMarks, 
             Collectors.mapping(Student::getName, Collectors.toList())));
person Holger    schedule 21.10.2016
comment
Я не понял, что вы имели в виду под типом результата комбинированного сборщика. Что это? - person Jude Niroshan; 21.10.2016
comment
Комбинированный коллектор — это groupingBy(Student::getMarks, mapping(Student::getName, toList())), который будет иметь тип результата, если рассматривать его как отдельное выражение (как и все выражения до Java 8). Если правила были такими, компилятор выдавал простое сообщение об ошибке Map<Integer, List<String>> не может быть присвоено Map<Integer,Map<String,List<String>>>. - person Holger; 21.10.2016
comment
К сожалению, правила Java 8 уже не так просты. Для так называемых «поли-выражений» целевой тип определяет тип результата, поэтому вы можете объявить groupping как Map<Object,List<CharSequence>> без какой-либо ошибки. Это позволит модифицировать типы функций ссылок на методы, например. Тогда Student::getMarks будет Function<Student,Object>, а Student::getName будет Function<Student,CharSequence>. Странное сообщение об ошибке связано с попыткой найти подходящие методы для вашего неправильного типа цели. - person Holger; 21.10.2016
comment
В моем случае; внутренний Collectors.mapping(Student::getName, Collectors.toList())) на самом деле вернет Map, не так ли? Но в качестве вашего решения вы предполагаете, что это List<String>, что меня смущает. - person Jude Niroshan; 21.10.2016
comment
Collectors.mapping не возвращает Map. Он сопоставляет элементы перед передачей их другому сборщику, поэтому он сопоставляет Students с именами String перед передачей их Collectors.toList(), который затем возвращает List<String> (а не List<Student>, как без сопоставления). Возможно, документация помогает. - person Holger; 21.10.2016
comment
Никогда не забывайте об этом: к сожалению, сообщение об ошибке «На нестатический метод нельзя ссылаться из статического контекста». - person Federico Pugnali; 21.11.2017
comment
Читая это снова после долгого времени, я думаю, вы случайно не видели способ, которым авторы могли бы улучшить передаваемое сообщение об ошибке? По крайней мере, до такой степени, чтобы реальный используемый нестатический метод мог быть отделен от несоответствий типов? Что касается кода, вы можете обратиться к github.com/openjdk/jdk, чтобы выделить области, которые можно улучшить. . - person Naman; 20.10.2020
comment
@Наман Я так и думал, стало лучше, но до этого еще далеко. Проблема в том, что существует формальная спецификация поведения правильных программ и теория синтаксического анализатора о том, как (эффективно) анализировать правильные программы, но работа с ошибочным вводом кажется в лучшем случае второстепенной темой. Всегда удивительно, как простые ошибки, такие как несоответствие скобок или неуместные разделители, сводят компиляторов с ума, несмотря на то, что такие проблемы должны быть легко обнаружены. Но это просто не то, как работает компилятор... - person Holger; 20.10.2020

Я думаю, что Хольгер дал хорошее объяснение ошибки и того, почему она не имеет большого смысла за один прогон.

Учитывая вашу цель, я думаю, что это решение, которое вам нужно.

 Map<Integer, Map<String, List<Student>>> grouping = students.stream().collect(Collectors.groupingBy(Student::getMarks,
                Collectors.groupingBy(Student::getName)));

Это просто даст вам список учеников, сначала сгруппированный по отметкам, а затем по именам. :))

person Supun Wijerathne    schedule 23.10.2016
comment
Как бы вы поступили, если бы у нас было это: Map<FavoriteBookEnum , Map<School, List<Student>>> вместо Map<Integer, Map<String, List<Student>>>? FavoriteBookEnum является перечислением внутри Student, а School просто классом с некоторой школьной информацией. Я пытаюсь получить карту, сгруппированную по любимым книгам, но... ничего не получается. - person TheNurb; 10.09.2020
comment
Для справки в будущем или для тех, у кого есть подобный сценарий - › заголовок stackoverflow.com/questions/63837641/ только что добавил вопрос об этом. - person TheNurb; 11.09.2020