本文主要介绍闭包,方法引用相关知识。 闭包是{ [closureParameters -> ] statements }
这种形式的代码块,可以接收参数,返回值,并且可以复制给某个变量,闭包里面可以引用外部的变量。具体可参考http://docs.groovy-lang.org/next/html/documentation/#_closures ,里面说的很详细。 闭包肯定会返回值,不像方法可能无返回值。
每个闭包都有这3个概念,this、owner和delegate,这3个概念很像,容易搞糊涂。
this:定义闭包的class对象owner:定义闭包的class对象或者闭包对象delegate:一个第三方对象,如果闭包内找不到方法或者属性就去delegate里面找。一个闭包的this指向的必然是一个class对象,而不是闭包对象,如下所示,
Enclosing内的闭包whatIsThis的this指向Enclosing对象。 而EnclosedInInnerClass里面,闭包cl定义在Inner里面,所以cl的this指针是Inner对象而不是EnclosedInInnerClass对象。NestedClosures里面的闭包cl是定义在另一个闭包nestedClosures里面的,所以cl的this是NestedClosures对象,而不是nestedClosures闭包class Enclosing { void run() { def whatIsThisObject = { getThisObject() } assert whatIsThisObject() == this def whatIsThis = { this } assert whatIsThis() == this }}class EnclosedInInnerClass { class Inner { Closure cl = { this } } void run() { def inner = new Inner() assert inner.cl() == inner }}class NestedClosures { void run() { def nestedClosures = { def cl = { this } cl() } assert nestedClosures() == this }}owner跟this基本一样,唯一不同就是owner可以是闭包。所以下边代码里的cl的owner就是nestedClosures。
class NestedClosures { void run() { def nestedClosures = { def cl = { owner } cl() } assert nestedClosures() == nestedClosures }}delegate是groovy里比较难理解的概念,简单的说如果一个闭包在执行的时候发现某个参数未定义,那么就会去他的owner以及delegate里面找(默认是先owner后delegate)。其实这么说起来delegate就是相当于java里的非静态内部类持有外部类的引用,delegate就是外部类的引用。默认情况下delegate就是owner。delegate在DSL里面是非常有用的。
如下所示,say这个闭包需要m变量,但是m未定义,如果直接执行say()肯定不行,在这里我们给say.delegate=eee,而eee这个map里边是有m这个变量的,所以在L9执行的时候,发现闭包内m未定义,就去他的delegate eee里找,找到了m,所以最后结果就是打印出2
def say = { PRintln m}//say.delegate = [m:2]eee=[m:2]assert eee.m==2say.delegate=eeesay()在这里,我们定义了一个闭包upperCasedName,通过指定delegate,改变闭包的执行主体,这看起来和传函数参数类似。闭包的delegate是可以不写的,因为闭包找不到成员的时候就会调用delegate的方法,所以闭包可以这么写
def upperCasedName = { name.toUpperCase() }我们知道在字符串插值的时候,可以用${}
占位,里面放任意表达式。实际上还可以用${->}
占位里面放闭包表达式。此时有一个特性,惰性求值(lazy evaluation).如下所示,对于普通的插值表达式eagerGString,被赋值为1之后,将不再改变。而对于闭包插值lazyGString来说,他每次GString转换为String的时候都会调用闭包,生成一个新的字符串
如果一个函数与一个闭包拥有相同的名称和参数,则调用的时候将执行函数,而不是闭包
.&
groovy支持方法引用,如下所示,upper就是一个方法引用,方法引用操作符的左边是个对象(还可以是this),右边是方法名。
注意下边fun是一个闭包,fun()是字符串‘EXAMPLE OF METHOD REFERENCE’
def str = 'example of method reference'def str2="s"def fun = str.&toUpperCasedef upper = fun()assert upper == str.toUpperCase()assert upper != str2.toUpperCase()println(upper)println(fun)println(fun())assert fun instanceof Closureassert fun() instanceof String方法无参数的时候,闭包就相当于一个简单的函数指针。
def f(){ println "Hello,world!";}def s=this.&f;s();这个就更吊了,只要有方法名,可以访问不同类型的对象,如下所示,reference是个闭包,往里面传个’foo’就会调用doSomething(String str)方法,往里头传个123,就会调用doSomething(Integer x)方法,这个简直是多态的升级版。
def doSomething(String str) { str.toUpperCase() } def doSomething(Integer x) { 2*x } def reference = this.&doSomething assert reference('foo') == 'FOO' assert reference(123) == 246如下所示filter是个闭包,他有且只有一个参数,这个参数就可以隐藏,用到的时候用it来指代(用法有点像this)
def filter = { it.contains 'G' }assert filter("Groovy")==trueA SAM type is a type which defines a single abstract method. This includes:
interface Predicate<T> { boolean accept(T obj)}http://docs.groovy-lang.org/next/html/documentation/#_closures groovy 官方sdk http://groovy.zeroleaf.com/ http://wiki.jikexueyuan.com/project/deep-android-gradle/four-two.html http://dublintech.blogspot.hk/2014/05/groovy-closures-this-owner-delegate.html
新闻热点
疑难解答