这里对Groovy闭包的基本使用操作进行介绍
声明定义
Groovy采用 { 参数列表 -> 语句 } 的形式定义一个闭包。需要注意的是,如果闭包中没有通过->显式声明参数列表, Groovy会默认提供一个名为it的缺省参数。故如果期望声明一个无参数的闭包,需要显式添加->来声明空参数列表, 以避免Groovy提供默认参数it
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 26
| class ClosureDemo { static void define() { def range1 = 1..2 println("\n----------------- Test 1 -----------------") range1.each { it -> println("Test 1: $it") }
println("\n----------------- Test 2 -----------------") range1.each { println("Test 2: $it") }
println("\n----------------- Test 3 -----------------") def closure3 = { -> println("Hello World") } closure3.call()
println("\n----------------- Test 4 -----------------") def closure1 = { num -> println("Test 4: $num") } assert closure1 instanceof Closure range1.each( closure1 )
println("\n----------------- Test 5 -----------------") Closure closure2 = { println("Test 5: $it") } assert closure2 instanceof Closure range1.each( closure2 ) } }
|
测试结果如下,符合预期
事实上,关于闭包的参数类型的数量,我们还可以通过闭包的getParameterTypes()方法进一步验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class ClosureDemo { static void other() { Closure closure1 = { print("Hello: $it") } assert closure1.getParameterTypes().size() == 1
Closure closure2 = { print("Hello") } assert closure2.getParameterTypes().size() == 1
Closure closure3 = { -> print("Hello") } assert closure3.getParameterTypes().size() == 0
Closure closure4 = { x,y,z -> print("Hello") } assert closure4.getParameterTypes().size() == 3 } }
|
调用
由于Groovy本身就是一个对象实例,故自然是可以直接调用的。具体地,可通过添加括号、call方法进行传参、调用。同时闭包在定义过程中还支持带有缺省值的参数。这样在进行闭包调用时,对于未给定的参数值, 闭包会使用缺省值
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 26 27
| class ClosureDemo {
static void call() { def closure1 = { "123" } assert closure1() == "123" assert closure1.call() == "123"
def closure2 = { x, y -> x+y } assert closure2(1,3) == 4
def closure3 = { String x, String y -> "${x}~~${y}" } assert closure3.call('2','7') == "2~~7"
def closure4 = { x, y=5 -> x*y } assert closure4.call( 4,7 ) == 28 assert closure4.call( 4) == 20 } }
|
返回值
对于闭包而言,闭包中如果未显式使用return语句, 返回最后一个表达式的结果;反之如果闭包中显式使用return语句, 返回指定值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class ClosureDemo { static void returnResult() { def closure1 = { -> def list = [] list.add("Bob") list.add("Aaron") } def result1 = closure1.call() assert result1 == true
def closure2 = { -> def list = [] list.add("Bob") list.add("Aaron") return list } def result2 = closure2.call() assert result2 == ["Bob", "Aaron"] } }
|
方法闭包
事实上我们还可以通过 .&方法指针运算符 获取方法的引用作为闭包,即所谓的方法闭包。与此同时,方法闭包支持重载,Groovy在运行时会选择合适的方法版本进行执行
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| class ClosureDemo { static void methodClosure() { def list = ["Tony", "Amy", "civilization", "Aaron"]
StrRule strRule1 = new StrRule(4) MethodClosure closure1 = strRule1.&validate assert closure1 instanceof Closure def list1 = list.findAll( closure1 ) assert list1 == ["Tony", "Amy"]
StrRule strRule2 = new StrRule(6) def list2 = list.findAll( strRule2.&validate ) assert list2 == ["Tony", "Amy", "Aaron"]
Handler handler = new Handler() def closure2 = handler.&handle def result1 = closure2.call("Aaron") assert result1 == "AARON" def result2 = closure2.call(12) assert result2 == 24 def result3 = closure2.call(3, 7) assert result3 == 10 } }
class StrRule{ int limit
StrRule(int limit) { this.limit = limit }
boolean validate(String str) { return str.size() <= limit } }
class Handler{ String handle(String str) { return str.toUpperCase() }
int handle(int num) { return 2 * num }
int handle(int x, int y) { return x + y } }
|
参考文献
- Groovy In Action · 2nd Edition Dierk König、Guillaume Laforge著