1.Closures的语法
格式语法:{ [closureParameters -> ] statements }
1{ name -> println name }
2.Closures对象和调用
Closures是一个对象(groovy.lang.Closure),是一个匿名代码块,类似于javascript的箭头函数,例子如下
1
2
3def demo = { it -> println it }
def 后紧跟着名称,这名称也是方法名,类似定义一个变量。
Closures调用方式如下
1
2demo(xxx); demo.call(xxx);
xxx是需要传的参数
3.Closures的参数
Closures的参数分为3种,分别为正常参数,隐式参数和可变参数
1)正常参数
有三个特性,1.类型可选,2.参数名,3.默认值(可选)
例子如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14def numAdd = { // 类型,默认值 int a, int b=2 -> a+b } def numAdd2 = { // 无类型,默认值 a,b=2 -> a+b } def numAdd2 = { // 无类型 a,b -> a+b } def numAdd3 = { // 有类型 int a, int b -> a+b }
2)隐式参数
隐式参数:it,这个it指代是传入的参数
代码如下:
1
2
3def greeting = { it -> "Hello, $it!" } assert greeting('Patrick') == 'Hello, Patrick!' // it代表传入的参数
3)可变参数
可变参数与java的可变参数一样,格式如下:type... name
例子如下
1
2
3
4def concat1 = { String... args -> args.join('') } assert concat1('abc','def') == 'abcdef' def concat2 = { String[] args -> args.join('') } assert concat2('abc', 'def') == 'abcdef'
4.委托策略
1)Closure的this指代的是什么?
在官网文档中有这样一句话
this
corresponds to the enclosing class where the closure is defined
大概意思,this对应的定义closure的闭包类(最近的)而且只能是类不能是closure,这个不论是内部类还是外部类;
借用官网的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19class EnclosedInInnerClass { //例子1 class Inner { Closure cl = { this } } void run() { def inner = new Inner() assert inner.cl() == inner } } class NestedClosures { // 例子2 void run() { def nestedClosures = { def cl = { this } cl() } assert nestedClosures() == this } }
例子1中的this指代的是Inner类,而例子2中this指代的是NestedClosures 。
2)Closure的Owner指代的是什么?
在官网文档中有这样一句话
owner
corresponds to the enclosing object where the closure is defined, which may be either a class or a closure
大概意思,owner对应的创建closure的所有者,这个所有者可能是一个类或者是一个closure
借用官网的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26class Enclosing {// 例子1 void run() { def whatIsOwnerMethod = { getOwner() } assert whatIsOwnerMethod() == this def whatIsOwner = { owner } assert whatIsOwner() == this } } class EnclosedInInnerClass {// 例子2 class Inner { Closure cl = { owner } } void run() { def inner = new Inner() assert inner.cl() == inner } } class NestedClosures {// 例子3 void run() { def nestedClosures = { def cl = { owner } cl() } assert nestedClosures() == nestedClosures } }
例子1中的owner指代的Enclosing类,例子2中的owner指代的是Inner类,例子3中的owner指代的是名为nestedClosures的closure
3)Closure的Delegate指代的是什么?
3.1) Delegate概念
在官网文档中有这样一句话
delegate
corresponds to a third party object where methods calls or properties are resolved whenever the receiver of the message is not defined
大概意思
delegate用于指定第三方对象使用。在一个Closure中使用没有定义的属性或者方法,在调用这个Closure之前,需要使用这个Closure的delegate属性指定一个对象,这个对象需要包含这个Closure之前所使用未定义的属性或者方法,这样整个调用链就完整了。
例子如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16class 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'
说明:
第一步:定义两个类Person和Thing,初始化对象p和t,定义一个Closure(upperCasedName)使用delegate的name属性,将值大写。但是delegate属性中并没有name属性。
第二步:将upperCasedName的delegate属性指定p和t,这时调用upperCasedName Closure,会将p和t对象初始化的值大写后返回。
更加直观的例子:
1
2
3
4def p = new Person(name:'Igor') def cl = { name.toUpperCase() } cl.delegate = p assert cl() == 'IGOR'
3.2)Delegate的委托策略
委托策略种类:
Closure.OWNER_FIRST默认策略,先在Closure的owner属性中检索Closure使用的方法和属性,找到直接返回,没有找到,再delegate属性中继续寻找。
Closure.DELEGATE_FIRST与Closure.OWNER_FIRST策略逻辑相反,先使用delegate属性,然后使用owner属性。
Closure.OWNER_ONLY 只在 owner属性中检索属性和方法
Closure.DELEGATE_ONLY 只在 delegate属性中检索属性和方法
Closure.TO_SELF用户自定的策略
默认策略例子如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17class Person { String name def pretty = { "My name is $name" } String toString() { pretty() } } class Thing { String name } def p = new Person(name: 'Sarah') def t = new Thing(name: 'Teapot') assert p.toString() == 'My name is Sarah' p.pretty.delegate = t assert p.toString() == 'My name is Sarah'
说明:
没有指定策略时使用默认策略,这个例子中虽然petty的delegate指定了Thing的实例t,但是petty的owner指向person的实例,在owner中找到相应的方法或者属性直接返回了,不在delegate中检索。
指定策略例子如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26class Person { String name int age def fetchAge = { age } } class Thing { String name } def p = new Person(name:'Jessica', age:42) def t = new Thing(name:'Printer') def cl = p.fetchAge cl.delegate = p assert cl() == 42 cl.delegate = t assert cl() == 42 cl.resolveStrategy = Closure.DELEGATE_ONLY cl.delegate = p assert cl() == 42 cl.delegate = t try { cl() assert false } catch (MissingPropertyException ex) { // "age" is not defined on the delegate }
说明:
在Person定义了fetchAge的Closure后有指定到cl上,cl没有指定策略时,cl的delegate无论指向Person实例p还是Thing实例t,调用的执行结果都是42。这是因为cl的owner指向了p.fetchAge
cl的指定了委托策略只在delegate中检索,cl的delegate执行p时执行没有问题,但是当delegate指向t时出现错误,没有age属性。
5.函数编程
5.1 Currying
currying英文原意是咖喱菜,但是这里的大概意思局部变量设置。
分为三种:LeftCurrying RightCurrying和IndexCurrying
这三种很好理解,例子如下
LeftCurrying:从Closure的参数列表的左侧设置值
1
2
3
4def nCopies = { int n, String str -> str*n } def twice = nCopies.curry(2) assert twice('bla') == 'blabla' assert twice('bla') == nCopies(2, 'bla')
RightCurrying:从Closure的参数列表的右侧设置值
1
2
3
4def nCopies = { int n, String str -> str*n } def blah = nCopies.rcurry('bla') assert blah(2) == 'blabla' assert blah(2) == nCopies(2, 'bla')
IndexCurrying:
1
2
3
4
5def volume = { double l, double w, double h -> l*w*h } def fixedWidthVolume = volume.ncurry(1, 2d) assert volume(3d, 2d, 4d) == fixedWidthVolume(3d, 4d) def fixedWidthAndHeight = volume.ncurry(1, 2d, 4d) assert volume(3d, 2d, 4d) == fixedWidthAndHeight(3d)
5.2 结果缓存
Closure的执行结果会缓存起来(使用memoize()方法)(同一个方法,相同的参数,执行的结果相同,不用重新计算一次),以便快速执行;例子如下:
1
2
3
4
5
6def fib fib = { long n -> n<2?n:fib(n-1)+fib(n-2) } assert fib(15) == 610 // 执行的慢 fib = { long n -> n<2?n:fib(n-1)+fib(n-2) }.memoize() assert fib(25) == 75025 // 执行的快
5.3 Closure组合
多个Closure组合起来,一起使用
例子如下:从大到小执行
1
2
3
4
5
6
7
8
9
10
11
12
13def plus2 = { it + 2 } def times3 = { it * 3 } def times3plus2 = plus2 << times3 //先执行times3,再执行plus2 assert times3plus2(3) == 11 assert times3plus2(4) == plus2(times3(4)) def plus2times3 = times3 << plus2 assert plus2times3(3) == 15 assert plus2times3(5) == times3(plus2(5)) // reverse composition assert times3plus2(3) == (times3 >> plus2)(3)
5.4 递归转化(Trampoline方法)
将原来的递归(方法没有执行完成全部堆积到内存中)转换为串行调用,防止出现堆栈溢出错误
例子如下:
1
2
3
4
5
6
7
8
9def factorial factorial = { int n, def accu = 1G -> if (n < 2) return accu factorial.trampoline(n - 1, n * accu) } factorial = factorial.trampoline() assert factorial(1) == 1 assert factorial(3) == 1 * 2 * 3
至此:Groovy的Closure全部学完,还有一些其他,如Closure嵌套等等。
最后
以上就是震动老鼠最近收集整理的关于groovy的Closure1.Closures的语法 2.Closures对象和调用3.Closures的参数4.委托策略5.函数编程的全部内容,更多相关groovy内容请搜索靠谱客的其他文章。
发表评论 取消回复