首先申明下,本文为笔者学习《Groovy 程序设计》的笔记,并加入笔者自己的理解和归纳总结。
闭包是Groovy的特性之一,类似于Java中的匿名内部类,但功能更加强大。
1. 闭包应用
一般用法
def filter(array, block) {
for (val in array) {
block(val)
}
}
iarray = [1, 2, 3, 4, 5, 6, 7, 8, 9]
total = []
filter(iarray, { if (it % 2 == 0) total << it })
println total // [2, 4, 6, 8]
total = []
filter(iarray, { if (it > 5) total << it })
println total // [6, 7, 8, 9]
当闭包作为最后一个参数时,可以有其它写法
filter(iarray) { if (it % 2 == 0) total << it }
闭包也可以作为属性,可以判断是否提供。
class Person {
def block
def setBlock(b) {
block = b;
}
def doSomeThing() {
if (block) {
block()
} else {
println "no block provide"
}
}
}
def p1 = new Person()
p1.doSomeThing() // no block provide
def block = { println "in block" }
def p2 = new Person()
p2.setBlock(block)
p2.doSomeThing() // in block
2. 闭包参数
单个参数,it
就是默认的参数名, 也可以指定特定的名称。
def printWithOneParameter(block) {
block("Michael")
}
printWithOneParameter { println it } // Michael
printWithOneParameter { name -> println name } // Michael
多个参数
def printWithTwoParameter(block) {
block "Michael", "Jordan"
}
printWithTwoParameter { firstName, secondName ->
println "$secondName, $firstName $secondName"
}
返回
Jordan, Michael Jordan
预先绑定相应的参数
def printWithTwoParameter(block) {
newBlock = block.curry("Michael")
newBlock "Jordan"
newBlock "Jackson"
}
printWithTwoParameter { firstName, secondName ->
println "$secondName, $firstName $secondName"
}
返回
Jordan, Michael Jordan
Jackson, Michael Jackson
类似的方法还有rcurry()
和ncurry()
def printWithTwoParameter(block) {
newBlock = block.rcurry("Michael")
newBlock "Jordan"
newBlock "Jackson"
}
printWithTwoParameter { firstName, secondName ->
println "$secondName, $firstName $secondName"
}
返回
Michael, Jordan Michael
Michael, Jackson Michael
ncurry()
调用格式是ncurry(index, block)
maximumNumberOfParameters
属性,闭包参数的数量。
def printWithTwoParameter(block) {
println block.maximumNumberOfParameters
}
printWithTwoParameter { firstName, secondName ->
println "$secondName, $firstName $secondName"
}
返回2
3. 闭包委托
闭包的三个属性this
、owner
和delegate
,用来确定那个对象处理该闭包的方法调用。
在内部的闭包中,owner
和delegate
的值被修改了。
def parameterClosure(closure) {
closure()
}
parameterClosure() {
println "In Outer Closure"
println "this is " + this
println "owner is " + owner
println "delegate is " + delegate
parameterClosure() {
println "In Inner Closure"
println "this is " + this
println "owner is " + owner
println "delegate is " + delegate
}
}
返回
In Outer Closure
this is ConsoleScript37@1372443
owner is ConsoleScript37@1372443
delegate is ConsoleScript37@1372443
In Inner Closure
this is ConsoleScript37@1372443
owner is ConsoleScript37$_run_closure1@3acd6fbe
delegate is ConsoleScript37$_run_closure1@3acd6fbe
类中调用闭包时,this
、owner
和delegate
三个属性的值都是上下文。
class ParameterClosure {
def handleClosure(closure) {
closure()
}
}
new ParameterClosure().handleClosure () {
println "this is " + this
println "owner is " + owner
println "delegate is " + delegate
}
返回
this is ConsoleScript43@1d476b4b
owner is ConsoleScript43@1d476b4b
delegate is ConsoleScript43@1d476b4b
方法的执行顺序,首先是this
,其次是owner
,最后是delegate
。可以设置delegate
来修改路由。
class Handler {
def f1() {
println "f1 in Handler"
}
def f2() {
println "f2 in Handler"
}
}
class ParameterClosure {
def handleClosure(closure) {
closure.delegate = new Handler()
closure()
}
}
def f1() {
println "f1 in script"
}
new ParameterClosure().handleClosure () {
f1()
f2()
}
返回
f1 in script
f2 in Handler
4. 上下文
上下文with
array = [1, 2, 3]
array.with {
add(5)
println delegate // [1, 2, 3, 5]
remove(1)
println delegate // [1, 3, 5]
}
设置delegate
实现上下文。
def withClosure(closure) {
array = [1, 2, 3]
closure.delegate = array
closure()
}
withClosure {
add(5)
println delegate // [1, 2, 3, 5]
remove(1)
println delegate // [1, 3, 5]
}
方法可以省略括号
def withClosure(closure) {
array = [1, 2, 3]
closure.delegate = array
closure()
}
withClosure {
add 5
println delegate // [1, 2, 3, 5]
remove 1
println delegate // [1, 3, 5]
remove 1
println delegate // [1, 5]
}