I'm trying to use method references to capture method invocations and am hitting some limitations. This works fine:
<T> void capture(Function<T, ?> in) {
}
private interface Foo {
String getBar();
}
capture(Foo::getBar);
But if I change the signature of Foo.setBar to something like this:
private interface Foo {
void setBar(String bar);
}
capture(Foo::setBar);
I get an error:
Cannot make a static reference to the non-static method setBar(String) from the type MyTest.Foo
It's not clear to me what the restriction is. Ideally I'd like to use method references to capture invocations on standard setter. Is there any way to do this?
There are two problems here:
- You're using
Function
, which has to return something.setBar
doesn't return anything. Function
only takes a single input, but you've got two inputs: theFoo
you'd callsetBar
on, and theString
argument you'd pass intosetBar
.
If you change to use BiConsumer
instead (which has a void
return type and two inputs) it works fine:
static <T, U> void capture(BiConsumer<T, U> in) {
}
You can overload your capture
method to have both signatures:
static <T, U> void capture(BiConsumer<T, U> in) { }
static <T> void capture(Function<T, ?> in) { }
and then use both method references:
capture(Foo::setBar);
capture(Foo::getBar);
Foo::getBar
corresponds to a function that takes a Foo
(the target object) and returns a String
. The interface Function<Foo, String>
can be used to represent such a function.
On the other hand, Foo::setBar
corresponds to a function that takes two arguments, a Foo
(the target object) and a String
(the first parameter). The matching interface is BiConsumer<Foo, String>
. That means you need an overload for BiConsumer
:
<T, U> void capture(BiConsumer<T, U> setter) {
// ...
}
Expose syntax sugar method reference, you should see, that
Foo::getBar
is equal to
(Foo)foo -> foo.getBar()
which is Function <Foo, String>
But
Foo::setBar
is in this context the function of two variables (foo
and some String str
), so it is not the function of one variable (Function
)
For the more convenient answer you should see, where the method references are allowed:
- Reference to a static method (not this case at all)
- Reference to an instance method of a particular object (not this case at all)
Reference to an instance method of an arbitrary object of a particular type (this case)
In the instruction above there is an example, which is almost the same as in your case. And it is said, that the equivalent lambda expression would be taking two parameters (in this case
Foo
andString
), which is notFunction
Reference to a constructor (not this case at all)
来源:https://stackoverflow.com/questions/23794186/limits-of-static-method-references-in-java-8