Java8: Is there a way to get an instance method reference from a class method reference?

If I have, for example, the following interface:

public interface FooBar<A, B> { B foo(A a); B bar(A a); } 

Is there any way to take a reference to a class class like FooBar::bar and get a reference to the instance method?

t. if i have

 FooBar myFooBarInstance; BiFunction<FooBar<A, B>, A, B> barFunction = FooBar::bar; 

Is there any easy way to get an instance of Function<A,B> that matches what I would get if I defined

 Function<A, B> myBarFunction = myFooBarInstance::bar; 
+6
source share
2 answers

What you want to do is called a “partial function application” in the world of program programming or simply “binds a value to a parameter” in less functional terms. There is no built-in method for this, but it is easy to write it yourself:

 public static <T,U,R> Function<U,R> bind(BiFunction<T,U,R> f, T t) { return u -> f.apply(t, u); } 

Then you can use it in your case:

 FooBar<X,Y> instance=…; BiFunction<FooBar<X,Y>,X,Y> barFunction=FooBar::bar; Function<X,Y> myBarFunction=bind(barFunction, instance); 

or simply

 // equivalent to myBarFunction=instance::bar Function<X,Y> myBarFunction=bind(FooBar::bar, instance); 

Please note that the utility method is limited to the functional interfaces that you use, i.e. Function and BiFunction , not method references. It works for any BiFunction , whether it is implemented as a reference to a method, a lambda expression or a regular class. But this will be useful only if you need an instance of Function , and not for an arbitrary functional interface that takes one parameter. You can convert Function to another type of function with one argument using ::apply , but using bind(bifunc, value)::apply does not give any advantages over x -> bifunc.apply(value, u) where you need it instance.

So, if you need to convert BiFunction to Function by binding the first argument very often, a useful method can be useful. Otherwise, just use the lambda expression in a context in which the real type of target is present. Of course, you can write a similar method for other interfaces, but again it will be useful only if you need it for this particular interface.

As for functions that take more parameters, since the Java API does not provide such functional interfaces, you will need to define the appropriate interface yourself, which offers the ability to provide the binding function directly in the interface as default methods, for example

 interface MyFunc3<A,B,C,R> { R apply(A a, B b, C c); default BiFunction<B,C,R> bind(A a) { return (b, c) -> apply(a, b, c); } } interface MyFunc4<A,B,C,D,R> { R apply(A a, B b, C c, D d); default MyFunc3<B,C,D,R> bind(A a) { return (b, c, d) -> apply(a, b, c, d); } } 

then if you have a function like

 MyFunc4<U, W, X, Y, Z> func = …; 

you can do something like

 MyFunc3<W, X, Y, Z> f3 = func.bind(u); 

or

 BiFunction<X, Y, Z> f2 = func.bind(u).bind(w); 
+7
source

I realized that the answer is pretty simple as soon as I thought about it. I can do it:

 Function<A, B> instanceFunction = (a)->barFunction.apply(myFooBar, a); 

It gets very ugly if you have methods that take more than a couple of parameters, but it works ...

+3
source

All Articles