Java8:有没有办法从类方法引用中获取实例方法引用?

时间:2016-03-11 02:26:29

标签: java java-8

例如,如果我有这样的界面:

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

    B bar(A a);
}

有没有办法采用像FooBar::bar这样的类级方法引用并获取实例方法引用?

即。如果我有

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

是否有任何简单的方法可以获得一个Function<A,B>实例,该实例与我定义的内容相匹配

Function<A, B> myBarFunction = myFooBarInstance::bar;

2 个答案:

答案 0 :(得分:7)

您想要做的是在函数编程领域中称为“部分函数应用程序”,或者在功能较少的术语中将“将值绑定到参数”。没有内置的方法,但很容易编写自己的方法:

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

然后你可以在你的情况下使用它:

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

或只是

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

请注意,实用程序方法对于您正在使用的功能接口(即FunctionBiFunction)是紧密的,而不是方法引用。它适用于任何BiFunction,可以实现为方法引用,lambda表达式或普通类。但是只有当你特别需要一个Function实例时才会有用,而不是一个带有一个参数的任意函数接口。您可以使用Function::apply转换为另一个单参数函数类型,但使用bind(bifunc, value)::apply在需要实例的地方不会比x -> bifunc.apply(value, u)提供任何好处。

因此,如果您必须经常通过绑定第一个参数将BiFunction转换为Function,则实用程序方法可能很有用。否则,只需在存在实际目标类型的上下文中使用lambda表达式。当然,你也可以为其他接口编写一个类似的方法,但是如果你经常需要它用于那个特定的接口,这将再次有用。

关于采用更多参数的函数,由于Java API不提供这样的功能接口,您必须自己定义适当的接口,这提供了在接口中直接提供绑定功能的选项default方法,例如

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);
    }
}

然后,如果你有像

这样的功能
MyFunc4<U, W, X, Y, Z> func = …;
你可以做点什么

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

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

答案 1 :(得分:3)

我意识到,一旦我想到答案,答案就非常简单了。我可以这样做:

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

如果你的方法需要多于几个参数,那真的很难看,但它有效......