Groovy闭包与方法引用
本文主要介绍闭包,方法引用相关知识。
闭包是{ [closureParameters -> ] statements }
这种形式的代码块,可以接收参数,返回值,并且可以复制给某个变量,闭包里面可以引用外部的变量。具体可参考http://docs.groovy-lang.org/next/html/documentation/#_closures,里面说的很详细。
闭包肯定会返回值,不像方法可能无返回值。
this、owner和delegate
每个闭包都有这3个概念,this、owner和delegate,这3个概念很像,容易搞糊涂。
this
一个闭包的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
owner跟this基本一样,唯一不同就是owner可以是闭包。所以下边代码里的cl的owner就是nestedClosures。
class nestedClosures {
void run() {
def nestedClosures = {
def cl = { owner }
cl()
}
assert nestedClosures() == nestedClosures
}
}
delegate
delegate是groovy里比较难理解的概念,简单的说如果一个闭包在执行的时候发现某个参数未定义,那么就会去他的owner以及delegate里面找(默认是先owner后delegate)。其实这么说起来delegate就是相当于java里的非静态内部类持有外部类的引用,delegate就是外部类的引用。默认情况下delegate就是owner。delegate在DSL里面是非常有用的。
例子1
如下所示,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==2
say.delegate=eee
say()
例子2
class Person {
String name
}
class Thing {
String name
}
def p = new Person(name: 'norman')
def t = new Thing(name: 'Teapot')
//闭包
def upperCasedname = { delegate.name.toupperCase() }
upperCasedname.delegate = p
assert upperCasedname() == 'norMAN'
upperCasedname.delegate = t
assert upperCasedname() == 'TEAPOT'
在这里,我们定义了一个闭包upperCasedname,通过指定delegate,改变闭包的执行主体,这看起来和传函数参数类似。闭包的delegate是可以不写的,因为闭包找不到成员的时候就会调用delegate的方法,所以闭包可以这么写
def upperCasedname = { name.toupperCase() }
字符串插值
我们知道在字符串插值的时候,可以用${}
占位,里面放任意表达式。实际上还可以用${->}
占位里面放闭包表达式。此时有一个特性,惰性求值(lazy evaluation).如下所示,对于普通的插值表达式eagerGString,被赋值为1之后,将不再改变。而对于闭包插值lazyGString来说,他每次GString转换为String的时候都会调用闭包,生成一个新的字符串
def number = 1
def eagerGString = "value == ${number}"
def lazyGString = "value == ${ -> number }"
assert eagerGString == "value == 1"
assert lazyGString == "value == 1"
number = 2
assert eagerGString == "value == 1"
assert lazyGString == "value == 2"
其他
如果一个函数与一个闭包拥有相同的名称和参数,则调用的时候将执行函数,而不是闭包
方法引用操作符.&
groovy支持方法引用,如下所示,upper就是一个方法引用,方法引用操作符的左边是个对象(还可以是this),右边是方法名。
对象.&方法名
注意下边fun是一个闭包,fun()是字符串‘EXAMPLE OF METHOD REFERENCE’
def str = 'example of method reference'
def str2="s"
def fun = str.&toupperCase
def upper = fun()
assert upper == str.toupperCase()
assert upper != str2.toupperCase()
println(upper)
println(fun)
println(fun())
assert fun instanceof Closure
assert fun() instanceof String
this.&方法名-方法无参数
def f(){
println "Hello,world!";
}
def s=this.&f;
s();
this.&方法名-方法有参数
这个就更吊了,只要有方法名,可以访问不同类型的对象,如下所示,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")==true
SAM(single abstract method)
A SAM type is a type which defines a single abstract method. This includes:
interface Predicate<T> {
boolean accept(T obj)
}
Thanks to
http://docs.groovy-lang.org/next/html/documentation/#_closures
groovy 官方sdk
http://groovy.zeroleaf.com/
http://www.voidcn.com/article/p-svqdmyjz-bnw.html
http://dublintech.blogspot.hk/2014/05/groovy-closures-this-owner-delegate.html
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。