-->

Static context cannot access non-static in Collect

2019-01-23 14:32发布

问题:

I have group of students. First I want to group them by the marks. Then I want to further group those sets into same name students together.

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

I am getting a error saying,

Non-static method cannot be refered from a static context.

Yes. I am pretty much aware that I cannot refer a non-static method without having an instance. But with all these stream operations, I'm bit confused what has gone wrong really.

Rather than how to fix this; I really want to know what's going on here. Any of your inputs are appreciated!

Because If I write the below grouping is completely valid;

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

Here is my Student.java class (In case if you need it)

public class Student {

    private String name;
    private int marks;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getMarks() {
        return marks;
    }

    public void setMarks(int marks) {
        this.marks = marks;
    }

    public Student(String name, int marks) {

        this.name = name;
        this.marks = marks;
    }

    @Override
    public String toString() {
        return name + ':' + marks ;
    }
}

回答1:

Unfortunately, the error message “Non-static method cannot be refered from a static context.” is just a place-holder for any type mismatch problem, when method references are involved. The compiler simply failed to determine the actual problem.

In your code, the target type Map<Integer, Map<String, List<String>>> doesn’t match the result type of the combined collector which is Map<Integer, List<String>>, but the compiler didn’t try to determine this (stand-alone) result type, as the (nested) generic method invocations incorporating method references requires the target type for resolving the method references. So it doesn’t report a type mismatch of the assignment, but a problem with resolving the method references.

The correct code simply is

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


回答2:

I think Holger has given a good explanation about the error and why it doesn't make much sense in one run.

Considering your goal, I think this is the solution you need to have.

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

This would simply give you a student list first grouped by marks, then by name. :))