如何传递和使用任意lambda函数作为参数[重复]
Posted
技术标签:
【中文标题】如何传递和使用任意lambda函数作为参数[重复]【英文标题】:How to pass and use an arbitrary lambda functions as parameter [duplicate] 【发布时间】:2016-01-04 08:47:16 【问题描述】:我对 Lisp 中的 lambda 函数有很好的了解。 Java 似乎没有 Lisp 那样的灵活性。我必须如何考虑 Java 中的 lambda? 鉴于下面的代码,我该怎么做?
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?
【问题讨论】:
请阅读这篇文章:***.com/questions/13604703/… 【参考方案1】:Java 中的 Lambda 与 functional interface 的概念结合使用。
典型的例子是Function
。 Function
是一个函数式接口,其函数式方法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);
【讨论】:
非常感谢。我想我明白了。对于我想作为参数传递的每个函数,我必须定义一个接口,其中只包含一个与我想使用的函数具有相同签名的函数定义。 @user2407434 您不必总是定义接口,您可以使用java.util.function
包中预先存在的接口。【参考方案2】:
您必须指定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);
GraphicsContext
的方法fillRect
必须与SomeFuncInterface
功能接口的方法签名兼容。
顺便说一句,GraphicsContext::fillRect
是方法引用,而不是 lambda 表达式。您可以传递 lambda 表达式、方法引用或功能接口的任何其他实现(常规类实例、匿名类实例等)。
【讨论】:
GraphicsContext::fillRect
无法编译,因为您无法对非静态方法 fillRect
进行静态引用。您需要使用gc::fillRect
,其中gc
是GraphicsContext
的一个实例。
@Tunaki 我的回答很笼统。我对GraphicsContext
类不熟悉,所以不知道fillRect
是不是静态的。以上是关于如何传递和使用任意lambda函数作为参数[重复]的主要内容,如果未能解决你的问题,请参考以下文章
将Lambda表达式作为参数传递并解析-在构造函数参数列表中使用Lambda表达式