如何在Java 8中直接将函数用作函数类型

Roh*_*bhu 5 java functional-programming java-8 method-reference

如果我创建一个功能界面:

@FunctionalInterface
public class Consumer2<T1, T2> {
    void accept(T1 t1, T2 t2);

    default Consumer1<T2> curry(T1 t1) {
        return (t2) -> accept(t1, t2);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我有一个班级:

public class MyClass {
    public void printStrings(String a, String b) {
        System.out.println(a + ": " + b);
    }
}

MyClass myClass = new MyClass();
Run Code Online (Sandbox Code Playgroud)

现在,如果我想使用我的功能界面,我可以:

Consumer2<String, String> printString = myClass::printStrings;
printString.curry("hello").accept("world");
Run Code Online (Sandbox Code Playgroud)

但我做不了类似的事情:

myClass::printStrings.curry("hello").accept("world");
Run Code Online (Sandbox Code Playgroud)

这是有道理的,因为Java无法知道myClass::printStrings可以应用于功能接口Consumer2.为此,我创建了一个实用程序类:

public class F {
    public static <T1, T2> Consumer2<T1, T2> c2(Consumer2<T1, T2> fn) {
        return fn;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我可以:

F.c2(myClass::printStrings).curry("hello").accept("world");
Run Code Online (Sandbox Code Playgroud)

甚至,这将工作:

((Consumer2<String, String>)myClass::printStrings).curry("hello").accept("world");
Run Code Online (Sandbox Code Playgroud)

只要有一些方法让Java 8在这种情况下理解该功能类型.所以,问题是,最好的方法是什么,同时可能避免使用样板?

Tag*_*eev 2

您涉及F.c2方法的解决方案很有趣,但您的示例太人为了。如果你问,如何更好地编写这段代码

F.c2(myClass::printStrings).curry("hello").accept("world");
Run Code Online (Sandbox Code Playgroud)

那么我肯定会建议你这样写:

myClass.printStrings("hello", "world");
Run Code Online (Sandbox Code Playgroud)

如果你想问如何将预定义参数绑定到方法引用,我建议你使用 lambda 函数:

Consumer1<String> fn = str -> myClass.printStrings("hello", str);
fn.accept("world");
Run Code Online (Sandbox Code Playgroud)

您可能想考虑在编译时未知您的函数的情况。在这种情况下,它要么从另一个方法返回,要么作为方法参数传递给当前方法,或者存储在变量/字段中。在所有这些情况下,它已经是功能接口,您可以curry直接使用:

Consumer2<String, String> getConsumer2() { return myClass::printStrings; }

getConsumer2().curry("hello").accept("world");
Run Code Online (Sandbox Code Playgroud)

因此,总的来说,我没有看到这里的问题。如果您仍然认为对方法引用应用柯里化很有用,我会curry在接口中创建一个静态方法(尽管我猜,它实际上是“绑定”,而不是“柯里化”)Consumer1

static <T1, T2> Consumer1<T2> curry(Consumer2<T1, T2> c2, T1 t1) {
    return c2.curry(t1);
}
Run Code Online (Sandbox Code Playgroud)

并像这样使用它:

Consumer1.curry(myClass::printStrings, "hello").accept("world");
Run Code Online (Sandbox Code Playgroud)