当前位置: 代码迷 >> 综合 >> Groovy 中的闭包
  详细解决方案

Groovy 中的闭包

热度:52   发布时间:2024-01-10 17:46:45.0

现在,闭包是 Java 世界的一个重大主题,对于是否会在 Java 7 中包含闭包仍然存在热烈的争论。有些人会问:既然 Groovy 中已经存在闭包,为什么 Java 语言中还需要闭包?这一节将学习 Groovy 中的闭包。如果没有意外,在闭包成为 Java 语法的正式部分之后,这里学到的内容将给您带来方便。

不再需要更多迭代

虽然在前几节编写了不少集合代码,但还没有实际地在集合上迭代。当然,您知道 Groovy 就是 Java,所以如果愿意,那么总是能够得到 Java 的 Iterator 实例,用它在集合上迭代,就像下面这样:

def acoll = ["Groovy", "Java", "Ruby"]

for(Iterator iter = acoll.iterator(); iter.hasNext();){
println iter.next()
}

实际上在 for 循环中并不需要类型声明,因为 Groovy 已经将迭代转变为任何集合的直接成员。在这个示例中,不必获取 Iterator 实例并直接操纵它,可以直接在集合上迭代。而且,通常放在循环构造内的行为(例如 for 循环体中 println)接下来要放在闭包内。在深入之前,先看看如何执行这步操作。








能否看见闭包?

对于上面的代码,可以用更简洁的方式对集合进行迭代,如下所示:

def acoll = ["Groovy", "Java", "Ruby"]

acoll.each{
println it
}

请注意,each 直接在 acoll 实例内调用,而 acoll 实例的类型是 ArrayList。在 each 调用之后,引入了一种新的语法 — { ,然后是一些代码,然后是 }。由 {} 包围起来的代码块就是闭包。







执行代码

闭包是可执行的代码块。它们不需要名称,可以在定义之后执行。所以,在上面的示例中,包含输出 it(后面将简单解释 it)的行为的无名闭包将会在 acoll 集合类型中的每个值上被调用。

在较高层面上,{} 中的代码会执行三次,从而生成如图 13 所示的输出。


图 13. 迭代从未像现在这样容易

闭包中的 it 变量是一个关键字,指向被调用的外部集合的每个值 — 它是默认值,可以用传递给闭包的参数覆盖它。下面的代码执行同样的操作,但使用自己的项变量:

def acoll = ["Groovy", "Java", "Ruby"]

acoll.each{ value ->
println value
}

在这个示例中,用 value 代替了 Groovy 的默认 it








迭代无处不在

闭包在 Groovy 中频繁出现,但是,通常用于在一系列值上迭代的时候。请记住,一系列值可以用多种方式表示,不仅可以用列表表示 — 例如,可以在映射、String、JDBC RowsetFile 的行上迭代,等等。

如果想在前面一节 “Groovy 中的映射” 中的 hash 对象上迭代,可以编写以下代码:

def hash = [name:"Andy", "VPN-#":45]
hash.each{ key, value ->
println "${key} : ${value}"
}

请注意,闭包还允许使用多个参数 — 在这个示例中,上面的代码包含两个参数(keyvalue)。







使用 Java 代码迭代

以下是使用典型的 Java 构造如何进行同样的迭代:

Map<String, String>map = new HashMap<String, String>();
map.put("name", "Andy");
map.put("VPN-#","45");


for(Iterator iter = map.entrySet().iterator(); iter.hasNext();){
Map.Entry entry = (Map.Entry)iter.next();
System.out.println(entry.getKey() + " : " + entry.getValue());
}

上面的代码比 Groovy 的代码长得多,是不是?如果要处理大量集合,那么显然用 Groovy 处理会更方便。








迭代总结

请记住,凡是集合或一系列的内容,都可以使用下面这样的代码进行迭代。

"ITERATION".each{
      
println it.toLowerCase()
}







闭包的更多使用方式

虽然在迭代上使用闭包的机会最多,但闭包确实还有其他用途。因为闭包是一个代码块,所以能够作为参数进行传递(Groovy 中的函数或方法不能这样做)。闭包在调用的时候才会执行这一事实(不是在定义的时候)使得它们在某些场合上特别有用。

例如,通过 Eclipse 创建一个 ClosureExample 对象,并保持它提供的默认类语法。在生成的 main() 方法中,添加以下代码:

def excite = { word ->
return "${word}!!"
}

这段代码是名为 excite 的闭包。这个闭包接受一个参数(名为 word),返回的 Stringword 变量加两个感叹号。请注意在 String 实例中替换 的用法。在 String 中使用 ${value}语法将告诉 Groovy 替换 String 中的某个变量的值。可以将这个语法当成 return word + "!!" 的快捷方式。







延迟执行

既然有了闭包,下面就该实际使用它了。可以通过两种方法调用闭包:直接调用或者通过 call() 方法调用。

继续使用 ClosureExample 类,在闭包定义下面添加以下两行代码:

assert "Groovy!!" == excite("Groovy")
assert "Java!!" == excite.call("Java")

可以看到,两种调用方式都能工作,但是直接调用的方法更简洁。不要忘记闭包在 Groovy 中也是一类对象 — 既可以作为参数传递,也可以放在以后执行。用普通的 Java 代码可以复制同样的行为,但是不太容易。现在不会感到惊讶了吧?