If I have, for instance, an interface like this:
public interface FooBar<A, B> {
B foo(A a);
B bar(A a);
}
Is there a way to take a class-level method reference like FooBar::bar
and get an instance method reference?
ie. if I have
FooBar myFooBarInstance;
BiFunction<FooBar<A, B>, A, B> barFunction = FooBar::bar;
is there any simple way to get a Function<A,B>
instance that would match what I'd get if I defined
Function<A, B> myBarFunction = myFooBarInstance::bar;
What you want to do is called “partial function application” in the function programming world or just “binding a value to a parameter” in less functional terms. There’s no built-in method for that, but it’s easy to write your own:
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 just
// equivalent to myBarFunction=instance::bar
Function<X,Y> myBarFunction=bind(FooBar::bar, instance);
Note that the utility method is tight to the functional interfaces you are using, i.e. Function
and BiFunction
, not to the method references. It works for any BiFunction
, be it implemented as method reference, lambda expression or ordinary class. But it will be useful only if you specifically need a Function
instance, not for an arbitrary functional interface taking one parameter. You can convert a Function
to another single-argument function type using ::apply
but using bind(bifunc, value)::apply
doesn’t offer any benefit over x -> bifunc.apply(value, u)
at the place where the instance is required.
So if you have to convert BiFunction
s to Function
s via binding a first argument very often, the utility method might be useful. Otherwise, just use a lambda expression in the context where the actual target type is present. Of course, you can write a similar method for other interfaces as well, but this will again only be useful if you need it for that specific interface often.
Regarding functions taking more parameters, since the Java API doesn’t provide such functional interfaces, you will have to define the appropriate interface yourself, which offers the option of providing the binding function directly in the interface as default
methods, e.g.
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);
I realized that the answer's pretty simple once I thought about it. I can do this:
Function<A, B> instanceFunction = (a)->barFunction.apply(myFooBar, a);
It gets really ugly if you have methods that take more than a couple parameters, but it works...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With