12

I have a list of Students which I want to convert into a Map<String, Integer>, where the map key should be the first name of the student. To keep the code sample simple, I specified the map value as 1:

final Map<String, Integer> map = someStudents.stream().collect(
        Collectors.toMap(Student::getFirstName, 1));

The compiler complains about:

non-static method getFirstName() cannot be referenced from a static context

Any idea? I am confused because many examples use the same approach of passing a reference to the non-static method. Why does the compiler see a static context here?

Ousmane D.
  • 54,915
  • 8
  • 91
  • 126
Emdee
  • 1,689
  • 5
  • 22
  • 35

3 Answers3

4

The value mapper should be a function, i.e.:

.collect(Collectors.toMap(Student::getFirstName, s -> 1));

The function s -> 1 essentially takes a student as input and returns 1 in this specific case for the map values.

The below code is not valid as the literal value 1 is not a function.

.collect(Collectors.toMap(Student::getFirstName, 1));
Ousmane D.
  • 54,915
  • 8
  • 91
  • 126
  • You are correct about second parameter but, the first parameter must be accessed through an object reference. Or, the `getFirstName` must be static. – lupchiazoem Jul 31 '18 at 14:29
  • @mnmopazem there's nothing wrong with `Student::getFirstName`, infact it's equivalent to `student -> student.getFirstName()` which indeed is an object reference. – Ousmane D. Jul 31 '18 at 14:33
  • Static members are accessed using class name. In this case, class name is `Student`, note the case. – lupchiazoem Jul 31 '18 at 14:36
  • @mnmopazem "Or, the getFirstName must be static." if `getFirstName` is defined as `static String getFirstName() {...}` it would yield a compilation error, first being that you cannot access instance fields in static methods and second in the `toMap` collector. the only case where the method can be `static` and still work is if you defined it as --> `static String getFirstName(Student s) { return s.getFirstName(); }` which I wouldn't recommend doing when you can simply define an instance getter method as `public String getFirstName() { return firstName; }` – Ousmane D. Jul 31 '18 at 14:53
  • That's interesting as compiler error contradicts method reference access type. May be, OP has error on different line?! What's your take? – lupchiazoem Jul 31 '18 at 14:53
  • Hm. I suppose both our answers are correct. Did you notice an interesting comment(on question) by Eugene? May be 'thats' the answer. :) – lupchiazoem Jul 31 '18 at 15:00
  • @mnmopazem well both our answers are correct but you saying " the correct statement is:" `someStudents.stream().collect( Collectors.toMap( student -> student.getFirstName(), student -> 1) );` suggests that using `Student::getFirstName` as the key mapper function is incorrect which is not true. Yes, I did realise what Eugene meant when i saw his comment earlier. you can read more here --> https://stackoverflow.com/questions/42200958/non-static-method-cannot-be-referenced-from-a-static-context-in-java-8-streams – Ousmane D. Jul 31 '18 at 15:03
  • @mnmopazem another similar issue answer by Holger --> https://stackoverflow.com/questions/40172551/static-context-cannot-access-non-static-in-collectors – Ousmane D. Jul 31 '18 at 15:04
4

Firstly, you are accessing getFirstName using a class name -Student(as if its a static memeber) rather than using object reference. Java tutorial - Method Refrences.
Secondly, second parameter of toMap method must be a Function type.

So, the correct statement is:
someStudents.stream().collect( Collectors.toMap( student -> student.getFirstName(), student -> 1 ) );

Edit:
Or, it can also be as posted by @Aomine. Both answers are correct. For more info, refer to comments on @Aomine's answers.

Edit 2:
Though, @Aomine's and this answer give expected result, note difference in first parameter.

lupchiazoem
  • 8,026
  • 6
  • 36
  • 42
1

The issue here is that first of all, this message is very misleading and that seems to be a java bug. Second, you are providing an int value in place of a function reference. Correct is this:

final Map<String, Integer> map = someStudents.stream().collect(
        Collectors.toMap(Student::getFirstName, val -> 1));

Here val -> 1 is a function which for any val will always return 1.

Another situation where you would get the same error would be this:

 final Map<String, Integer> map = someStudents.stream().collect(
            Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

If someStudents is of type Map<String, String> but map is Map<String, Integer> you would get the same:

non-static method Map.Entry::getValue cannot be referenced from a static context

ACV
  • 9,964
  • 5
  • 76
  • 81