groovy闭包内部如何工作?

时间:2017-03-18 11:38:07

标签: java groovy lambda closures internal

Java lambda无法修改周围范围内的变量(不会关闭)。但是Groovy关闭怎么样呢?它的内部实施是什么?

例如,在这里,闭包如何增加外部变量i?是否会为每次迭代创建一个内部对象?

for (int i = 0; i < n;) {
    { -> i++ }.run()
}

1 个答案:

答案 0 :(得分:3)

在这种情况下,i被装在一个可变的groovy引用中。在Java中,设置i将改变此循环所在方法的局部变量。这提出了一系列关于如果函数对象离开方法会发生什么的技术问题。但是在groovy中,i驻留在堆上。

这个解释来自我理解的字节码,您可以使用以下命令获取:

javap -c <name of closure class>

查看方法doCall,首先查找仿函数的CallSite对象(因为lambdas可以共享它们的类,调用站点基本上是捕获的局部变量的集合),以及特定的{ {1}}已被检索:

i

如您所见,10: getfield #29 // Field i:Lgroovy/lang/Reference; 的类型为i。接下来,数字递增:

groovy.lang.Reference

之后,结果将重新加载到Groovy引用中:

27: invokestatic  #51                 // Method org/codehaus/groovy/runtime/DefaultGroovyMethods.next:(Ljava/lang/Number;)Ljava/lang/Number;

这类似于在Java中做这样的事情:

42: invokevirtual #61                 // Method groovy/lang/Reference.set:(Ljava/lang/Object;)V

我使用for (AtomicInteger i = new AtomicInteger(); i.get() < n;) { ((Runnable) () -> System.out.println(i.getAndIncrement())).run(); } 来表示驻留在堆上的可变AtomicInteger,而不是局部变量槽。