图片.png闭包是Groovy语言最常用的用法之一,Closure是闭包的意思。
闭包是一个短的匿名代码块。它通常跨越几行代码。一个方法甚至可以将代码块作为参数。它们是匿名的。
(1)初识闭包
下面是一个最简单闭包的例子,它是什么样子呢?
def clos = {println "Hello World"};
clos.call();
在上面的例子中,代码段 {println“Hello World”}
被称为闭包。此标识符引用的代码块可以使用call语句执行。
(2)each中的Closure
当遍历List或者Map集合时,需要使用each()
方法,如下图所示:
each()
方法的形式参数传递一个Closure
对象,在Groovy语言中,Closure
对象就是闭包
。
最终代码是:
def map = ["name":"张三", "age":24]
map.each {
println it.key+":"+it.value
}
输出结果为:
name:张三
age:24
(3)自定义Closure
def closure = {
println "我是一个闭包"
}
closure.call()
闭包可以作为一个变量被定义,closure.call()
的意思是执行闭包
。
输出结果为:
我是一个闭包
(4)向闭包中传递参数
使用call方法向闭包传递参数,代码如下:
def closure = {
name -> print "我的名字叫:${name}"
}
closure.call("张三")
(5)对it
的理解
[案例一]
def list = [1,2,3,4,5,6,7,8]
list.each {
println it
}
打印结果如下:
1
2
3
4
5
6
7
8
each()
方法遍历list中的每个元素,所以it是集合中的某个元素。
[案例二]
def map = ["name":"张三", "age":24]
map.each {
println it.key+":"+it.value
}
打印结果如下:
name:张三
age:24
each()
方法遍历map中的每个元素,map中的元素是Map.Entry
类型的,所以这里的it就是Map.Entry
类型的元素。
[案例三]
定义一个方法:
private static def customClosure(Closure closure){//类型可以省略,如customClosure(closure)
closure("床前明月光") //在闭包中添加第一个元素
closure("疑似地上霜") //在闭包中添加第二个元素
closure("举头望明月") //在闭包中添加第三个元素
closure("低头思故乡") //在闭包中添加第四个元素
}
调用这个方法:
customClosure {
println "诗词:"+it
}
打印结果如下:
诗词:床前明月光
诗词:疑似地上霜
诗词:举头望明月
诗词:低头思故乡
closure(param)
方法向闭包里面传递元素,闭包的元素是一个集合,这里的it
就代表闭包里面的某个元素。
另外,打印闭包的内容也可以不使用it,如下:
customClosure {
param -> println "${param}"
}
这是一个参数的情况,如果多个参数,如下:
private static def transformParam(Closure closure){
closure(1, "床前明月光") //在闭包中添加第一个元素
closure(2, "疑似地上霜") //在闭包中添加第二个元素
closure(3, "举头望明月") //在闭包中添加第三个元素
closure(4, "低头思故乡") //在闭包中添加第四个元素
}
这种情况,如果使用it的话就不太合适了,我们应该这样打印数据:
transformParam {
param1, param2 -> println "${param1}:${param2}"
}
打印结果如下:
1:床前明月光
2:疑似地上霜
3:举头望明月
4:低头思故乡
(6)多参数的情况
如果方法的参数有多个参数,那么分为以下几种情况:
[第一个参数是闭包,第二个参数是非闭包]
private static def muiltiMethod(closure, name){
closure(name)
}
调用方法:
muiltiMethod({
println it
}, "张三")
如果方法的最后一个形参不是闭包,那么不能隐藏()
,以上代码调用muiltiMethod
时,小括号不能隐藏。
[方法的最后一个参数是闭包]
这里的重点就是这个了。
当方法中只有一个形参,并且这个形参是闭包,那么就默认认为:方法的最后一个参数是闭包
。
private static def muiltiMethod(name, closure){
closure(name)
}
上面定义个方法有两个参数,最后一个参数是闭包,那么调用这个方法的代码写法是这样的:
muiltiMethod("张三", {
println it
})
然而,Groovy还有一个特性,那就是,当方法的最后一个参数是闭包,那么闭包可以放在小括号的外面,改进后的代码如下:
muiltiMethod("张三") {
println it
}
(7)闭包委托
Groovy的强大之处在于它支持闭包方法的委托。Groovy闭包有三个非常重要的属性,分别是:thisObject、owner、delegate
thisObject:相当于this,指向类对象本身;
owner:可以指向类对象,也可以指向一个闭包,默认和this一样,但如果闭包定义在闭包的内部,那么owner就会指向闭包;
delegate:默认情况下和owner差不多,owner和delegate是一样的,但是,delegate到底指向谁,程序员可以控制。
有关闭包委托,我们能控制的只有delegate,所以delegate经常被使用到。
thisObject、owner、delegate说白了作用域的控制,默认情况下,它们的作用域是一样的,如图所示:
图片.png闭包中(代码块)中有三个属性(thisObject、owner、delegate),它们的作用域都是当前类对象。
这三个属性的优先级是thisObject-->owner-->delegate
,所以,如果外部类一旦访问了这个代码块,Groovy首先在thisObject
中找,实际上,Groovy已经在thisObject
作用域中找到了该代码块,所以也就没有owner
和delegate
什么事了。
那么,再来一张图,如下:
图片.png当类中闭包中还有一个闭包时,owner
和delegate
的指向发生改变。
假设图中闭包内的闭包
表示a,当访问a时,首先在thisObject
中寻找,可惜找不到,接下来在,owner
中寻找,结果找到了,所以就没有delegate
什么事了。
但是,有时候,为了增加访问效率,我们需要修改委托策略,从而改变访问顺序。
a是可以设置委托策略的,代码如下:
closure.setResolveStrategy(Closure.OWNER_FIRST)
委托策略的含义有:
- Closure.OWNER_FIRST 是默认策略。如果属性或者方法存在于 owner 内,那么他可以被 owner 调用,如果不存在,则会尝试在 delegate 类中查找
- Closure.DELEGATE_FIRST 颠倒了默认逻辑:delegate 是第一优先级,其次才是 owner
- Closure.OWNER_ONLY 将仅仅在 owner 查找需要的属性或者方法:delegate 会被忽略
- Closure.DELEGATE_ONLY 将仅仅在 delegate 查找需要的属性或者方法:owner 会被忽略
- Closure.TO_SELF 可以被用于当开发人员需要使用先进的元数据编程技术和希望实现一个自定义的选择策略时:这个选择将不是 owner 或者 delegate,而仅仅是 closure 类自己。当我们实现了自己的 Closure 子类时,他才是有意义的。
假如,将a的委托策略设置为Closure.OWNER_FIRST
,那么访问a时,首先在owner
中寻找,这样就优化了访问速率。
接下来,重点来了,delegate
是闭包委托的重点,先看一下如下代码:
private static def trustClosure(Closure<Student> closure){
Student student = new Student();
student.name = "张三"
student.age = 23
//将Student对象放入delegate中
closure.delegate = student;
//设置委托策略,让delegate优先被访问
closure.setResolveStrategy(Closure.DELEGATE_FIRST)
closure(student)
}
看一下这个方法,将将Student对象放入delegate中,并设置委托策略,让delegate优先被访问,当外部访问这个方法时,可以迅速的访问这个方法,并且可以修改被委托的对象属性
//闭包委托
Hello.trustClosure {
Student student = (Student)it;
student.name = "李四"
println "学生的姓名:"+student.name
println "学生的年龄:"+student.age
}
[本章完...]
网友评论