Benjamin
Benjamin

Reputation: 1726

Java 8 Method reference to instance method of an arbitrary object of a particular type

Why does the following not work?

import java.util.function.Function;

public class MethodRefTest {
   public String passMeAround( String input ) {
      return input + " been passed to me";
   }

   public Function<String, String> testReferences() {
      final Function<String, String> f1 = MethodRefTest::passMeAround;
      return f1;
   }

   public static void main( String[] args ) {
      new MethodRefTest()
            .testReferences()
            .apply( "foo" );
   }
}

Javac tells me:

MethodRefTest.java:14: error: invalid method reference
      final Function<String, String> f1 = MethodRefTest::passMeAround;
                                          ^
  non-static method passMeAround(String) cannot be referenced from a static context
1 error

I don't understand why the context is static. I read this but it does not seem to answer the problem at hand.

EDIT

Also according to oracle, "Reference to an instance method of an arbitrary object of a particular type" are possible via ContainingType::methodName

EDIT 2

@marko-topolnik helped me understand my mistake here. Function<String, String> f1 = MethodRefTest::passMeAround; refers to a static method String MethodRefTest.passMeAround(String)

BiFunction<MethodRefTest, String, String> f1 = MethodRefTest::passMeAround;

on the other hand, refers to the instance method of any instance, that is passed in the apply clause.

BiFunction<MethodRefTest, String, String> f2 = MethodRefTest::passMeAround;
//call instance method
f2.apply(new MethodRefTest(), "some string");

Upvotes: 8

Views: 1598

Answers (3)

Marko Topolnik
Marko Topolnik

Reputation: 200158

Because you referred to it as

MethodRefTest::passMeAround

You should have referred to it as

this::passMeAround

providing the instance to use for context.

A different way to view your current code is to say that MethodRefTest::passMeAround is a BiFunction<MethodRefTest, String, String> and this lambda shape does not match the target site. So, alternatively, you may have written

public BiFunction<MethodRefTest, String, String> testReferences() {
  return MethodRefTest::passMeAround;
}

and in the main method

final MethodRefTest t = new MethodRefTest();
t.testReferences().apply( t, "foo" );

The material you have been reading may not be instructive enough, so let me expand. With

this::passMeAround

you get a lambda object which has captured the this instance from the context where it was created, but with

MethodRefTest::passMeAround

you get a "pure", non-capturing lambda which represents the invocation of the specified method on some instance, with some string argument, so when you apply it, you need to pass in both.

Upvotes: 18

ka4eli
ka4eli

Reputation: 5424

Change passMeAround to static:

 public static String passMeAround( String input ) {
      return input + " been passed to me";
   }

or refer to it as to instance method:

 public Function<String, String> testReferences() {
      final Function<String, String> f1 = this::passMeAround;
      return f1;
 } 

Upvotes: 0

cxw
cxw

Reputation: 17041

To answer your question about why the context is static, it's because the part before the :: was the name of a class rather than the name of an instance. If you don't have an instance, only static members are accessible.

Upvotes: -1

Related Questions