Java Lambda 表达式是否与 Groovy 闭包的逻辑相似?

2022-09-03 09:43:00

我正在学习 Java 8 新功能 Lambda 表达式。这是我使用 Lambda 表达式的“HelloWorld”类

public class LambdaHelloWorld {
    interface HelloWorld {
        String sayHello(String name);
    }

    public static void main(String[] args) {          
         HelloWorld helloWorld = (String name) -> { return "Hello " + name; };
         System.out.println(helloWorld.sayHello("John Doe"));
    }
}

这种风格与Groovy开合非常相似。这是时髦的“HelloWorld”

def sayHello(name) {
        println("Hello $name!")
}

def clos = {name -> sayHello(name)} 
clos.call('John Doe')

我认为这两个代码之间的差异较小。Java Lambda 表达式是否与 Groovy 闭包的逻辑或风格相似?


答案 1

在Java 8(使用lambdas)或Groovy(带有闭包)中实现所谓的函数式接口看起来非常相似,但底层机制却大不相同。让我们以功能接口为例。我们用它来调用一个名为 的假设实例上的新 Java 8 方法。java.util.function.ConsumerforEach()java.util.ListmyList

在Java中,它看起来像这样:

myList.forEach ((s) -> System.out.println(s));

在Groovy中也是如此:

myList.forEach { s -> println s }

两个编译器都从 lambda /闭包代码生成新的类。Java 8 生成的类实现了目标接口(在本例中),而不是从任何内容派生,类似于这样的嵌入式匿名类:Consumer

myList.forEach(new Consumer<Object>() {
    @Override
    public void accept (Object s) {
        System.out.println(s);
    }
});

相比之下,Groovy生成的内容看起来有点像下面这样:

myList.forEach (new Closure(this) {
    void doCall(Object s) {
        println s
    }
}

这将创建一个从中派生的匿名类,该类不实现任何特定接口。但是,它可以在这里用作参数。这是可能的,因为Groovy在运行时生成一个动态代理对象,实现“Consumer”接口并将任何调用转发到生成的闭包实例。groovy.lang.Closure

因此,你可以用Groovy闭包替换Java 8 lambdas,但不能反过来。当您想要在 Java 8 代码中使用 Groovy API 时,您不能调用期望使用 lambda 表达式进行闭包的方法。 不是一个函数接口,而是一个抽象类,这根本不能由lambda表达式实现。Closure


答案 2

Java的lambdas也是闭包。这些在抽象层面上是相同的功能,但是在细节上,并且取决于确切的版本,Groovy可能只是在创建临时实现类,而Java 8指定了一个完整的机制,由lambda Metafactory,lambda factory和涉及获取lambda Metafactory的机制组成。invokedynamic


推荐