# 闭包
- 闭包的基础知识
- 闭包的使用
- 闭包 this,owner,delegate 的理解
- 总结
## 闭包的基础知识
闭包就是一段可以使用参数的代码片段,每个闭包会被编译成继承groovy.lang.Closure 类的类(具体查看编译后的.class文件即可),这个类有一个叫 call 方法,通过该方法可以传递参数并调用这个闭包。
### 定义一个闭包
闭包定义的格式
//方式1:定义参数
{闭包参数,闭包参数,闭包参数...->闭包体}
//方式2:无定义参数,${it] 为默认的参数
{闭包体}
指定闭包参数
def closure = {String name,int age->
println "name is ${name} and the age is ${age}"
}
不指定闭包参数
def closure2 = {
println "the param is ${it}"
}
闭包就是一个对象
//指定闭包的类型
Closure<Boolean> isImageFile = {
String filePath ->
return filePath.endsWith('.png') || filePath.endsWith('.jpg')
}
println isImageFile("xxxx.png")//true
### 闭包的返回值
闭包一定是有返回值的,这就是闭包有别于方法的一点,方法是可以没有返回值的。
def closuer = {String name,int age->
println "name is ${name} and the age is ${age}"
}
//因为没有调用 return ,因此返回 null
println closuer('六号表哥',26)//null
### 闭包的参数
- 闭包的参数是可选的;
- 有一个默认的参数;
- 闭包多个参数使用 , 隔开;
- 参数的类型是可选的;
- 闭包参数接受可变参数
//不指定参数类型,多个参数用,个隔开
def clouser = { name, age ->
println "name is ${name} and the age is ${age}"
}
//不指定闭包参数
def clouser = {
println "closure"
}
//闭包 it 为暗指参数
def clouser2 = {
println "the param is ${it}"
}
//可变参数
def concat = { String... params ->
params.join()
}
println concat.call("1","2","3")//123
### 调用闭包
在 Groovy 中调用闭包有两种方式
- closuer.call(参数)
- closuer()
def closuer = {String name,int age->
println "name is ${name} and the age is ${age}"
}
//调用方式1
closuer.call('六号表哥',26)//name is 六号表哥 and the age is 26
//调用方式2
closuer('六号表哥',26)//name is 六号表哥 and the age is 26
//使用 ${it} 表示默认参数
def closuer2 = {
println "the param is ${it}"
}
closuer2('使用默认参数')//the param is 使用默认参数
## 闭包的使用
- 闭包与基本数据类型的集合
def result = 0;
//从10递增到20,累加每一个值
10.upto(20) {
int value ->
result += value
}
println result
- 闭包与
String
字符串的结合
String name = "Hello Groovy"
//name.each {
// String str ->
// print str + " "//H e l l o G r o o v y
//}
//查找第一个符合条件的值
println name.find {
String str ->
if (str.equals("o")) {
return str
}
return null
}
println name.findAll {
if (it.equals("o")) {
return it;
}
return null
}.toListString()//[o, o, o]
String book = "20180701"
println book.every {
String str ->
return str.isInteger()//true
}
println name.any {
return it.equals("o")//true
}
String str = "name:liuhaobiaoge,age:26,level:middle,1:update,0:canel"
str.findAll {
if (it.isInteger()) {
return it;
}
return null
}.collect {
String value ->
print value.toInteger() * 2 + " "//4 12 2 0
}
- 闭包与结合数据结构集合
def list = [1, 2, 3, 4]
println list.every { it ->
return it > 0
}
- 闭包与文件结合
TODO
### 通过源码分析 upto 方法是如何使用闭包的?
upto
方法它的职责很单一就是一个递增的功能,但是每递增一次,对应的需要给外界知道,那么就是通过执行一段闭包,将这个值暴露出去,这种设计很好,它不会影响upto
方法内部的执行逻辑。
- 调用 uptp 方法,传入闭包
def result = 0;
//从10递增到20,累加每一个值
10.upto(20) {
int value ->
result += value
}
println result
- 进入 upto 源码
代码很简单,具体每一行代码都加了注释
/**
* Iterates from this number up to the given number, inclusive,
* incrementing by one each time.
*
* @param self a Number
* @param to another Number to go up to
* @param closure the closure to call
* @since 1.0
*/
public static void upto(Number self, Number to, @ClosureParams(FirstParam.class) Closure closure) {
//self的值就是10
int self1 = self.intValue();
//to1的值就是20
int to1 = to.intValue();
//满足条件
if (self1 <= to1) {
//从10遍历到20
for (int i = self1; i <= to1; i++) {
//每一个值传递给我们先前定义的闭包closure,并执行该闭包。
closure.call(i);
}
} else
...
}
## this,delegate,ower 的区别
### 定义
this
表示定义闭包的类owner
表示定义闭包的类或者闭包(闭包内还是可以定义闭包的)delegate
默认与owner
一致,可以手动修改delegate
的值
### 区别
- 一般情况下这三者是一样的。
- 闭包中定义在闭包中,
this
和ower
,delegate
不一致。 - 如果修改
delegate
,那么ower
和delegate
就不一致。
默认情况下
this
,owner
,delegate
是一样的。
class Enclosing {
void run() {
def closure = {
println this//Enclosing@69997e9d
println owner//Enclosing@69997e9d
println delegate//Enclosing@69997e9d
}
closure()
}
}
闭包中的this就是定义闭包的类对象
验证1:测试闭包的 this 和定义闭包的类的 this 是否一致
class Enclosing {
void run() {
def whatIsThisObject = { getThisObject() }
assert whatIsThisObject() == this
println whatIsThisObject()//Enclosing@3514a4c0
//this就是Enclosing对象
println this//Enclosing@3514a4c0
def whatIsThis = { this }
//返回闭包的this对象
println whatIsThis()//Enclosing@3514a4c0
}
}
new Enclosing().run()
验证2:使用内部类来验证闭包的this和定义闭包的类的this是一样的
class EnclosdInnerClass {
class Inner {
//这里返回的this就是Inner对象
def closure = { this }
}
void run() {
def inner = new Inner()
println inner.closure()//EnclosdInnerClass$Inner@6babf3bf
//打印内部类对象
println inner//EnclosdInnerClass$Inner@6babf3bf
//这个是外部类对象
println this//EnclosdInnerClass@3059cbc
}
}
new EnclosdInnerClass().run()
验证3:验证闭包的this和定义闭包的类的this是一样的
class Person {
String name
int age
String toString() {
"${name} is $age year old"
}
String dump() {
def closure = {
//this 表示就是定义closure 闭包的类,这个类就是Person
//因此这里调用的toString就是Person的toString()方法
def msg = this.toString()
println msg
return msg
}
closure()
}
}
//如果不知道构造参数,那么在传参时就要执行参数的名称
Person p = new Person(name: "六号表哥", age: 26)
p.dump()//六号表哥 is 26 year old
闭包中的 owner 就是定义闭包的闭包或者类对象
验证1:
class OwnerEnclosing {
void run() {
def whatIsOwnerMethod = {
getOwner()
}
//返回闭包的owner对象
println whatIsOwnerMethod()//OwnerEnclosing@6e0f5f7f
//返回定义闭包类的对象
println this//OwnerEnclosing@6e0f5f7f
def whatIsOwner = { owner }
println whatIsOwner()//OwnerEnclosing@6e0f5f7f
}
}
OwnerEnclosing ownerEnclosing = new OwnerEnclosing()
ownerEnclosing.run()
验证2:
class OwnerEnclosdInnerClass {
class Inner {
def closure = { owner }
}
void run() {
def inner = new Inner()
//返回 closure 这个闭包的owner对象
println inner.closure()//OwnerEnclosdInnerClass$Inner@53ce1329
//返回内部类,也就是定义闭包的类对象
println inner//OwnerEnclosdInnerClass$Inner@53ce1329
}
}
new OwnerEnclosdInnerClass().run()
验证3:
class NestedClosure {
void run() {
def closure = {
def cls = { owner }
//返回的cls闭包的owner,也就是closure闭包对象
cls()
}
println closure()//NestedClosure$_run_closure1@32502377
println closure//NestedClosure$_run_closure1@32502377
}
}
new NestedClosure().run()
闭包中的 deleagate 一般情况下和 owner 一致的,但是可以修改
class DelegateEnclosing {
void run() {
def cls1 = { getDelegate() }
def cls2 = { delegate }
println cls1()//DelegateEnclosing@7bab3f1a
println cls2()//DelegateEnclosing@7bab3f1a
println this//DelegateEnclosing@7bab3f1a
def enclosed = {
//这里返回的是定义闭包的闭包对象,也就是enclosed闭包对象
{ -> delegate }.call()
}
println enclosed()//DelegateEnclosing$_run_closure3@12aba8be
println enclosed//DelegateEnclosing$_run_closure3@12aba8be
}
}
new DelegateEnclosing().run()
验证:闭包的delegate是可以修改的
class P {
String name
}
class Q {
String name
}
P pp = new P(name: "pp")
Q qq = new Q(name: "qq")
def closure = {
delegate.name.toUpperCase()
}
//将闭包的deleagte指向pp
closure.delegate = pp
println closure()//PP
closure.delegate = qq
println closure()//QQ
## 总结
在本节中,简单的总结了闭包的相关概念,定义,使用,以及this,owner,delegate几个关键字的理解。闭包在 Groovy 中应用很广泛,本节将闭包的应用分为与基本数据类型结合的闭包,与String 字符串结合的闭包,与数据结构结合的闭包,与文件结合的闭包(还没学习,不知道怎么耍,TODO),仅仅通过上面所总结的还是不够的,接下来还要好好深入学习其 Closure 相关的知识点。
「记录于2018-07-01晚」