闭包在groovy语言经常使用,其重要性不言而喻。
1 闭包概念
闭包是一个可执行的代码块,可以通过变量引用,也可以传递给别的函数处理。闭包大大的简化了容器的遍历,提升了代码的可扩展性。
2 定义闭包
用大括号括起来的代码
def clo = {println("hello wold")}
3 闭包调用
call()方法或者直接()
clo.call()
clo()
4 闭包的参数
def clo = { para -> println "$para" } //定义一个有参数的闭包
参数和方法之间用 -> 连接,参数类型可省略,当只有一个参数时,可以用关键字 it 来访问该参数,一个参数时也可以省略,多个参数时用逗号隔开。
def clo = { println it } //只有一个参数可以用it访问
clo.call(1) //输出 1
def clo1 = { para1,para2 -> println para1 + para2 }
clo(1,2) //返回1+2的值
def clo2 = { para1,para2,para3=3 -> para1+para2+para3 }//带默认参数的闭包
clo2.call(1,2) //计算 1+2+3
clo.call(1,2,4) //这样会覆盖参数para3
5 闭包返回值
闭包一定有返回值,可采用return显性返回,如果没有return,就默认最后一条语句的值为返回值为
def clo = { println "hello wold" } //返回值为null,注意null也是一个值
def clo1 = {para -> para + 1 } //返回值为 para + 1
6 闭包与函数的区别
了解闭包与函数有哪些不同,就可以理解闭包相比于函数的优势。
6.1 闭包可以嵌套,函数不可以
def clo = { para -> { para + it } } //嵌套
clo(2)(3) //调用
6.2 闭包可以访问外部变量,函数不可以
def x = 5
def clo = { it + x }
clo.call(10)
下面就是错误的
def x = 5
def func(){ println "$x" } //编译无法通过,找不到x
注意:方法访问局部变量的方法
将变量的作用域改成全局
采用闭包传递参数
x = 5
def func(){ println "$x" } //编译通过,这是因为不用def定义的变量其实是全局变量
通过闭包传递参数:
def x = 5
def clo = { x } //这样就获取到x的值
def func(clo){ clo.call() + 1 } //将x的值加1
func(clo)
6.3 调用方式不同
闭包调用:
clo.call()
clo()
函数用函数名称调用
function()
function para //省略括号也是允许的
6.4 返回值不同
闭包一定有返回值,前面已经说到了,函数可以没有返回值,void类型的函数没有返回值。
6.5 参数不同
闭包可以有参数,如果没有定义参数,则有一个默认参数it。函数可以没有参数。
7 闭包科里化
科里化也是闭包的一个重要特点,我们可以开发更多功能。科里化即将多个变量的函数拆解为单变量的函数依次调用。关键字curry。
//科里化示例
def clo = { x,y -> x*y }
def curryclo = clo.curry(2) //对clo进行科里化,等价于 curryclo = { y -> 2*y } 第一个参数被2替代
curryclo.call(3) //计算2*3
科里化的用处:
//实现闭包符合
def clo1 = {x->x*x}
def clo2 = {y->y+y} //定义两个闭包,利用curry实现两个闭包的组合
def clo3 = {f,g,e -> f(g(e))} //定义组合后的闭包,即定义组合规则
def clo4 = clo3.curry(clo1,clo2) //相当于 (y+y)*(y+y)
clo4.call(2)
//去冗余,将复杂参数去除
def clo5 = {p1,p2->println "$p1+$p2"}
Data data = new Data()
def curryclo5 = clo5.curry(data)
curryclo5("hello")
curryclo5("world")
//制造函数工厂
def clopow = {x,y -> y**x} //y的x次方
def clo22 = clopow.curry(2) //生成一个计算平方的函数
def clo33 = clopow.curry(3) //生成一个计算三平方的函数
8 闭包的作用
最常见的用处就是迭代集合
回调:在函数中call闭包
实现高阶函数
特殊的控制逻辑
动态方法定义
资源分配
线程处理
9 闭包的坑
9.1 return:在闭包循环中使用return并不会退出循环
def list = [1,2,3,4]
list.each{
if(it == 3)
return it //遇到此处并没有退出,执行结果为124
print(it)
}
跳出循环则用return true
each中return true相当于continue
find中return true相当于break
9.2 隐藏参数it
当且仅当闭包中有且仅有一个参数,且不显示声明,it具有唯一参数引用的作用,其他情况下,如果在闭包参数声明中没有it,那么闭包的逻辑代码块中的it降级为普通的变量
def clo = {p1 ->
def it = 1
return it + p1 //it为普通变量
}
println clo.call(3) //结果为1+3
当外部也定义了it,则优先使用外部的变量
it = 1
def clo = {p1 -> println "$it"}
clo.call(3) //结果为1
闭包嵌套时内部闭包的参数it与外部闭包it不会相互影响
def clo = {
println it
def clo2 = {
println it
}
clo2.call() //输出null,不会获得外部it的值
}
clo.call(3) //输出:3 null