groovy中的闭包,也就是Closure。接触过lambda或者kotlin的同学肯定知道,在java中如果有类似于setxxxListener之类的方法,直接传入一个接口(如果接口只有一个方法,就叫做函数式接口)。然后接口里方法外包装的一层完全没有作用,然后lambda表达式出现解决了这个问题,在java8中就可以使用。Closure就类似于这种形式,不过闭包中有更多的实现,下面来总结一下。
一、闭包的使用
(一) 简单闭包的定义使用,当然闭包和方法意向,最后一个值默认为返回值
def closure={
println "this is a closure"
}
closure.call()
closure()
结果:
this is a closure
this is a closure
(二) 闭包参数、默认参数、传参、指定参数
def closure={
i="5",j->
println "closure $i $j"
}
//map键值对会优先传给第一个参数,无论顺序,普通方法也是类似的
//有默认参数例外
closure('i':"5",'j':"10",5)
closure('i':"5",'j':"10")
closure("ja")
def newClosure = closure.ncurry(1,'6')
newClosure('7')
结果:
closure [i:5, j:10] 5
closure 5 [i:5, j:10]
closure 5 ja
closure 7 6
(三) 与接口互相替代
1、普通替代
interface Ic{
void call()
}
interface IIc{
void call()
}
def test(c){
c()
}
def test2(IIc c){
c()
}
test {
println "closure"
}
test(new Ic(){
@Override
void call() {
println "closure"
}
})
test2{
println "closure"
}
结果:
closure
closure
closure
2、多个方法替代
interface IcTeste{
void test1();
void test2();
void test3();
}
def test( c){
c.test1();
c.test2();
c.test3();
}
def closure={
println "test"
} as IcTeste
test(closure)
结果:
test
test
test
二、闭包的代理机制
closure有着独特的代理机制,我们戳进Closure这个类的时候,就会发现注释写的非常详细,而且还带有例子,直接看注释就能理解绝大部分内容了,良心呀,有例子的更能看明白,真的稳。
首先我看这段
* To be able to use a Closure in this way with your own
* subclass, you need to provide a doCall method with any
* signature you want to. This ensures that
* {@link #getMaximumNumberOfParameters()} and
* {@link #getParameterTypes()} will work too without any
* additional code.
其实这里稍微有点不明白,倒是是doCall还是call,实际上要用call方法才对呀,不过也不是重点了。我主要关注这两个方法,这两个方法就是获取闭包的参数个数以及类型了,直接测试一下。说实话我没有找到显示指定闭包参数类型的方法,有没有大神告知一下,万分感谢。
def c ={
i ,j->
println "groovy $i $j"
}
println c.getMaximumNumberOfParameters()
println c.getParameterTypes()
结果:
2
[class java.lang.Object, class java.lang.Object]
代理的策略
闭包有三个变量,默认情况下
this 定义它的时候 所在的类的this 静态闭包当中为 class
owner 定义它的时候 所在类的对象
delegate 默认就是owner
使用delegate我们可以执行很多不同的操作,代理的策略总共有5个。
OWNER_FIRST 所有者优先
DELEGATE_FIRST 代理者优先
OWNER_ONLY 仅所有者
DELEGATE_ONLY 仅代理者
TO_SELF 仅自身
先看对于变量的影响。
class Test {
def x = 30
def y = 40
def run() {
def data = [x: 10, y: 20]
def cl = { y = x + y }
cl.delegate = data
cl.resolveStrategy = Closure.DELEGATE_FIRST
switch (cl.resolveStrategy) {
case Closure.DELEGATE_FIRST:
println "DELEGATE_FIRST"
break;
case Closure.DELEGATE_ONLY:
println "DELEGATE_ONLY"
break;
case Closure.OWNER_ONLY:
println "OWNER_ONLY"
break;
case Closure.TO_SELF:
println "TO_SELF"
break;
case Closure.OWNER_FIRST:
println "OWNER_FIRST"
break;
}
println "cl=" + cl()
println "x" + x
println "y" + y
}
}
new Test().run()
分别用5种策略测试结果
DELEGATE_FIRST|DELEGATE_ONLY
cl=30
x30
y40
===============================
OWNER_ONLY|OWNER_FIRST
cl=70
x30
y70
===============================
TO_SELF
Caught: groovy.lang.MissingPropertyException: No such property: x for class: Test$_run_closure1
一路看下来就很明确了,对于局部变量来说会根据策略的不同来选择,其实很简单。那么对于方法呢:
class Delegate {
def fun() {
println "delegate"
}
}
def fun(){
println "owner"
}
def cl = {
def fun = {
println "self"
}
fun()
}
cl.delegate = new Delegate()
cl.resolveStrategy = Closure.OWNER_FIRST
switch (cl.resolveStrategy) {
case Closure.DELEGATE_FIRST:
println "DELEGATE_FIRST"
break;
case Closure.DELEGATE_ONLY:
println "DELEGATE_ONLY"
break;
case Closure.OWNER_ONLY:
println "OWNER_ONLY"
break;
case Closure.TO_SELF:
println "TO_SELF"
break;
case Closure.OWNER_FIRST:
println "OWNER_FIRST"
break;
}
cl()
这样写不管策略是什么,都会调用self,也就是局部变量是锁定了,我们把
def fun = {
println "self"
}
这个闭包去掉,结果就不同了。
DELEGATE_FIRST|DELEGATE_ONLY
delegate
============================
OWNER_ONLY|OWNER_FIRST
owner
============================
TO_SELF
Caught: groovy.lang.MissingMethodException: No signature of method: test$_run_closure1.fun() is applicable for argument types: () values: []
闭包如果想要手动指定delegate,owner,this可以通过rehydrate(),该方法传递三个参数,分别对应delegate,owner,this。返回一个新的闭包来进行使用。
def fun(Closure c) {
def b=c.rehydrate('123','234','456')
b.call()
}
fun {
println this
println delegate
println owner
}
结果:
456
123
234
利用这个特性,如果熟悉Gradle的人,就可以理解DSL的基本原理了。
那么闭包就总结到这里了,如果有错误欢迎在评论区指正。