1. 闭包的初步认识
闭包通常用于函数式语言中,它允许执行一个制定好的代码块。
通俗的说,一个闭包就是一个用花括号括起来的语句块,为了传递参数给闭包,闭包有一个可选的参数列表,通过“->”表示列表的结束
闭包的简单实例:
面向对象的最高原则是对象有自己的行为和数据,闭包也是对象,其目的是其行为。可以把闭包理解为一个类中的方法。但是始终记住:闭包是由一些代码组成的对象。
2. 闭包的缺省参数it
下面两个closure作用是一样的
[1,2,3].each{println it}
[1,2,3].each{i->println i}
等效的java代码:
List<Integer> list=new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
for(Integer i:list){
System.out.println(i);
}
3. 闭包的用途
3.1 处理集合,迭代
上面的例子都是关于集合的实例
3.2 处理资源
在Java中打开流必须对应一个close来关闭流来释放资源。通过groovy闭包可以实现:
newFile("D:\\carinfo.txt").eachLine { println it }
eachLine会处理流的打开及关闭。
4. 声明闭包
4.1 花括号声明
在一个方法调用的后面,放置闭包代码在一对花括号里,闭包的参数和代码通过箭头进行分割。箭头是闭包的参数和代码的分隔指示符。
4.2 声明变量
使用复制的方式声明闭包,将其赋给一个变量。
def printer={line -> println line}
4.3 方法返回值
通过方法返回值
def Closure getPrinter(){
return {line -> println line}
}
4.4 引用一个方法作为闭包
重用已有的声明:一个方法。方法有一个方法体,可选的返回值,能够接受参数,并且能被调用。调用方法:
class MethodClosureSample{
int limit
MethodClosureSample(int limit){
this.limit=limit
}
boolean validate(String value){
return value.length()<=limit
}
}
MethodClosureSample first=new MethodClosureSample(6)
MethodClosureSample second=new MethodClosureSample(5)
Closure firstClosure=first.&validate
def words=["long string","medium","short","tiny"]
println(words.find(firstClosure))
println(words.find(second.&validate))
4.5 闭包缺省参数
def adder={x,y=5->return x+y}
println(adder(4,3)) //直接调用
println(adder.call(2)) //call方式调用
5.闭包的调用
直接调用和使用call方法调用
实例1:
def adder={x,y->return x+y}
println(adder(4,3)) //直接调用
println(adder.call(2,6)) //call方式调用
实例2:从一个方法内部调用一个闭包
def benchmark(repeat,Closure worker){
start=System.currentTimeMillis()
repeat.times{worker(it)}
stop=System.currentTimeMillis()
return stop-start
}
slow=benchmark(10000){(int)it/2}
fast=benchmark(10000){it.intdiv(2)}
println(fast)
println(slow)
6.curry
curry的基本思想是一个多个参数的函数,传递较少的参数给函数来固定一些值。
在groovy中,Closure的curry方法返回当前闭包的一个克隆品,这个克隆品已经绑定一个或多个给定的参数。
def adder={x,y->return x+y}
def addCurry=adder.curry(1)
println(addCurry(6))
一个复杂的例子:
def configurator={format,filter,line->
filter(line)?format(line):null
}
def appender={config,append,line->
def out=config(line)
if(out)append(out)
}
def dateFormatter={line->"${new Date()}:$line"}
def debugFilter={line->line.contains('debug')}
def consoleAppender={line->println line}
def myConf=configurator.curry(dateFormatter,debugFilter)
def myLog=appender.curry(myConf,consoleAppender)
myLog("here is some debug message")
myLog("this will not be printed")
7.变量作用域
def x=0
10.times {x++}
println x
花括号显示了闭包声明的时间,不是执行的时间。在闭包的声明期间,闭包可以对变量x进行读和写操作(没理解这句的意思)。
闭包在它的生命周期里以某种方式记住了它的工作上下文环境,当调用它时,闭包可以在它的原始上下文中工作。
这种声明周期的上下文需要闭包记住相应地一个引用,而不是一个复制品,如果工作上下文是原始上下文的一个复制品,
从闭包中是没有办法改变原始上下文的。声明周期上下文必须被引用。
在闭包中,this将引用到当前对象,这是对包对象本身。
名称为owner的变量可以获取到声明闭包的对象。
8.从闭包返回结果
闭包最后一个表达式执行的结果,并且这个结果被返回,叫做结束返回,在最后的语句前面的return关键字是可选的。
使用return关键字从闭包的任何地方返回
在闭包内使用return关键字和在闭包外使用是有区别的。在闭包内使用return,仅结束闭包的当前计算,例如在list.each中,return不影响闭包在下一个元素时被调用
ps:《Groovy in action》读书笔记