78

Always when I use lambda expressions like this:

.map(obj -> foo.makeSomething(obj))

IntelliJ suggests: "Can be replaced with method reference...". And when I try then:

.map(Foo::makeSomething)

I get the following statement: "Non-static method cannot be referenced from a static context".

Why Idea suggests me I should use method reference if it's not correct?

user
  • 4,410
  • 16
  • 57
  • 83
  • 11
    Does it actually suggest that replacement? Or is that just what you are writing yourself? I would have expected `foo::makeSomething`, which would work. – Andy Turner Jul 02 '17 at 20:18
  • 4
    It's `foo::makeSomething`. You want to call the method on the object foo, not on the class Foo. You could also just let IntelliJ transform the code for you (Alt-Enter). – JB Nizet Jul 02 '17 at 20:19
  • Possible duplicate of [Java 8 Method Reference to non-static method](https://stackoverflow.com/questions/26168806/java-8-method-reference-to-non-static-method) – Andrew Li Jul 02 '17 at 20:21
  • which version of IntelliJ IDEA are you using? – Mike Nakis Jul 02 '17 at 20:22
  • @JBNizet TY for that shortcut - jeez for the life of me I couldnt figure out how to tell IJ to do it! All it gave was a useless popup even more useless suggestion to go to settings where there was nothing relevant to this exact code !! Leaning more and more towards Eclipse now :( which so nicely has the right-click option – killjoy Jun 30 '18 at 15:02

1 Answers1

101

As you write :

map(Foo::makeSomething)

the compiler expects one of these two possibilities :

  • invoking a Foo.makeSomething() instance method on the first parameter of the lambda that has to be so defined as a Foo.

  • invoking a Foo.makeSomething() static method.

The first possibility is eliminated by the compiler as the first parameter of the lambda declared obj is not a Foo.

And according to your error message, Foo.makeSomething() is an instance method :

Non-static method cannot be referenced from a static context"

So, the second possibility (invoking a Foo.makeSomething() static method) is not legal either as makeSomething() is not static.


In fact, what you want is applying the makeSomething() instance method on a variable that doesn't make part of the lambda parameters.
You can do it but you need to use another syntax.

Instead of specifying Foo::, use foo::.
In this way, the instance method makeSomething() will be applied on the foo variable :

map(foo::makeSomething)

IntelliJ Intention

Note that inspection that reports lambdas which can be replaced with method references can also be automatically refactored by the IDE via an intention.
To do that, set the cursor on the lambda (anywhere on it) and display contextual intentions (Alt+Enter by default). You should see the intention :

Replace lambda with method reference

Some screenshots :

intention proposition

intention result

davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • 6
    Thank you so much, I didn't know that I can use reference with object. I wa thinking it works only when I call ClassName::metohd. – user Jul 02 '17 at 20:38
  • 1
    You are welcome :) In fact, you have three cases to apply method references: 1)static method, 2)instance method for parameters of the lambda and 3)instance method for a variable not declared in the lambda parameters. And for the last case, the syntax is indeed different. – davidxxx Jul 02 '17 at 20:47
  • As @Eli already said, if the method is in the same Class then you have to use 'this' instead of the Class name. – CodeSlave May 23 '20 at 10:07