如何传递和使用任意lambda函数作为参数

时间:2015-10-07 08:01:14

标签: java lambda java-8

我对Lisp中的lambda函数有很好的理解。 Java似乎没有Lisp那样的灵活性。我如何在Java中考虑lambdas? 鉴于下面的代码,我该怎么做?

public class Draw {
    GraphicsContext gc;

    static void draw(double x, double y, double w, double h, boolean drawRect) {
        if (drawRect) {
            gc.fillRect(x, y, w, h);
        } else {
            gc.strokeRect(x, y, w, h);
        }
    }

    // How do I do that?
    static void drawWithLambda(double x, double y, double w, double h /**, lambda */) {
        lambda(x, y, w, h);
    }

    public static void main(String[] args) {
        draw(0, 0, 50, 50, false); // OK
        drawWithLambda(0, 0, 50, 50, GraphicsContext::fillRect); // Ok?
    }
}

2 个答案:

答案 0 :(得分:3)

您必须指定lambda方法参数实现的功能接口的类型:

drawWithLambda(double x, double y, double w, double h, SomeFuncInterface lambda) {
    lambda.someMethod (x, y, w, h); // someMethod is the single method that
                                    // SomeFuncInterface implements
}

为了让这条线路正常工作

drawWithLambda(0, 0, 50, 50, GraphicsContext::fillRect);

fillRect的方法GraphicsContext必须与SomeFuncInterface功能界面的方法签名兼容。

BTW,GraphicsContext::fillRect是方法引用,而不是lambda表达式。您可以传递lambda表达式,方法引用或函数接口的任何其他实现(常规类实例,匿名类实例等)。

答案 1 :(得分:3)

Java中的Lambda与functional interface的概念结合使用。

典型的例子是FunctionFunction是一个功能接口,其功能方法apply是一个接受单个参数并返回结果的方法。

您可以创建自己的功能界面,谁将定义一个带有4个参数且没有返回类型的函数方法,如下所示:

@FunctionalInterface
interface RectangleDrawer {
    void draw(double x, double y, double w, double h);
}

FunctionalInterface注释并非绝对必要,但它有明确的意图。)

然后,您可以创建符合此功能接口合约的lambda。典型的lambda syntax(method arguments) -> (lambda body)。在此示例中,它将是:(x, y, w, h) -> gc.fillRect(x, y, w, h)。这是因为lambda声明了4个参数并且没有返回类型,所以它可以表示为之前定义的RectangleDrawer的函数方法。

你的例子将成为:

static GraphicsContext gc;

public static void main(String[] args) {
    draw(0, 0, 50, 50, (x, y, w, h) -> gc.fillRect(x, y, w, h));
    draw(0, 0, 50, 50, (x, y, w, h) -> gc.strokeRect(x, y, w, h));
}

static void draw(double x, double y, double w, double h, RectangleDrawer drawer) {
    drawer.draw(x, y, w, h);
}

在这种特殊情况下,可以使用method reference创建lambda,使用::运算符,它允许编写更简单的代码:

static GraphicsContext gc;

public static void main(String[] args) {
    draw(0, 0, 50, 50, gc::fillRect);
    draw(0, 0, 50, 50, gc::strokeRect);
}

static void draw(double x, double y, double w, double h, RectangleDrawer drawer) {
    drawer.draw(x, y, w, h);
}