第二章:闭包
非正式向导
在使用JAVA编程时,很多执行的代码上都披上的修饰符:要么是静态的方法(类方法),要么是实例方法。(代码同样可以加上构造器,初始值,初始的表达式,但这些在这儿不重要了)。处在波括号中的一个封装代码的方法并指派这一段代码一个方法名。所有这些方法必须在某一类型中的一个类中定义,举例来说,如果你想写一个方法,返回一个整型的square,如下所示:
package example.math;
public class MyMath {
public static long square(int numberToSquare){
return numberToSquare * numberToSquare;
}
}
现在为了使用这个square()方法,你需要靠名字来引用这个类和方法,如下:
import example.math.MyMath;
...
int x, y;
x = 2;
y = example.math.MyMath.square(x);
// y will equal 4.在Groovy中,你同样可以这样做,但你还可以在声明类和方法之前定义这段代码,这就是所谓使用closure(闭包),一个闭包是一个或多个包含在波括号中的程序语句,闭包和方法最主要的不同之处在于:闭包不需要一个类或方法名,下面展示了作为闭包所写的square()方法:
Unable to find source-code formatter for language: groovy. Available languages are: xhtml, javascript, java, none, html, actionscript, xml, sql
{numberToSquare ->
numberToSquare * numberToSquare
};
这时,你可以看到,这段可执行的代码除了你不需要去声明一个类或指派一段代码一个方法名外,其余的是一样的。根据你看到注释可知,上面的例子不那么用因为一旦它建立后就没有办法使用那个闭包。它没有一个标识符(方法名),那么,我们如何来调用它呢?要做到这一点,你可以在它被创建时赋予闭包一个变量。然后,你就可以视那个变量为这个闭包的标识符用来调用,如下所示:
Unable to find source-code formatter for language: groovy. Available languages are: xhtml, javascript, java, none, html, actionscript, xml, sql
// initiate variables
int x, y;
x = 2;
// create closure and assign it to variable C
def c = {numberToSquare -> numberToSquare * numberToSquare }
// using C as the identifer for the closure, make a call on that closure
y = c.call(x);
// y will equal 4;
闭包的优点在于,你可以创建一个闭包,赋予它一个变量,然后在其它任何变量中进行传递,刚开始,你觉得没什么,但当你对Groovy有了深入的了解,你将会发现,闭包在所有地方是很有用的。
举个例子,假设在Groovy中来扩充java.lang.Vector这个类,我们加入一个简单的方法,允许你在vector中对所有的元素应用一个闭包,一个新类:GVector,如下:
package example;
public class GVector extends java.lang.Vector {
public GVector(){
super();
}
public void apply( c ){
for(int I = 0; I < this.size(); I++){
old_element = this.elementAt(i);
new_element = c.call(old_element);
this.set( I, new_element);
}
}
}
方法apply()带了一个闭包作为输入的参数,在GVector中的每一个元素,闭包在元素中被调用来进行传递,而作为结果返的的值然后用来代替这个元素,这样做是为了让你能够在适当的时候,使用这个带了某一元素的闭包,修改GVector中的内容,并且可以转换成其它的东西。
现在,我们可以用任何我们想到的闭包来调用这个新的apply()方法,举例来说,我们将创建一个新的GVector,它有一些元素,在闭包中传递的是我们先前创建好的那个square。
Unable to find source-code formatter for language: groovy. Available languages are: xhtml, javascript, java, none, html, actionscript, xml, sql
example.GVector gVect = new example.GVector();
gVect.add(2);
gVect.add(3);
gVect.add(4);
c = {numberToSquare -> numberToSquare * numberToSquare;}
gVect.apply(c);
// the elements in the GVector have all been squared.
因为在GVector中的apply()方法可以随任意闭包使用,你能够使用任何的闭包。看下面的例子,它使用了一个闭包,打印出它传递的消息。
Unable to find source-code formatter for language: groovy. Available languages are: xhtml, javascript, java, none, html, actionscript, xml, sql
example.GVector gVect = new example.GVector();
gVect.add(2);
gVect.add(3);
gVect.add(4);
c2 = {value -> println(value);}
gVect.apply(c2);
// the elements in the GVector have all been printed.
如果你去运行上面的脚本,假定你定义并编译这个GVector类,输入将会像以下所示:
C:/> groovy myscript.groovy
4
9
16
C:/>
除了赋予闭包一个变量外,你也可以在方法中作为参数直接声明,如上面的代码可以改写为以下形式:
Unable to find source-code formatter for language: groovy. Available languages are: xhtml, javascript, java, none, html, actionscript, xml, sql
example.GVector gVect = new example.GVector();
gVect.add(2);
gVect.add(3);
gVect.add(4);
gVect.apply {value -> println(value);}
// the elements in the GVector have all been printed.
这个例子结果与第一个一样,但闭包是作为参数直接定义并应用在GVector中的apply方法上的。
闭包与代码块(Closures vs. Code Blocks)
闭包很像规则的JAVA或者Groovy代码块,但事实上不同。在规则的代码块中的代码(不管它是一个方法块,类块,同步块,还是仅仅一段代码块)一旦被虚拟机碰到就会被执行。就闭包来说,在波括号中的语句段不会被执行,直到闭包中的call()方法被调用。在上一个例子中,闭包声明在同一行中,但却没有在那个时候执行,只有当call()方法被明确调用时,它才执行。这是闭包与代码块一个很重要的不同!他们看起来好像差不多,但事实上不是这样的。规则JAVA和Groovy块一旦被碰到就被执行了,而闭包没有这样,它只有在由call()方法调用时,才被执行。
正式向导
Groovy中,一个闭包是一段匿名代码,它可以带参数(可以有多个),可以返回一个值,可以引用,可以使用在它相应的范围内所定义的变量.在很多方式上有点类似JAVA中的内部类.在使用上,Groovy中的闭包使用起来与JAVA开发者使用匿名内部类有同工之处,然而,Groovy中的闭包比起匿名内部类来,有更加强大的功能,并且具有在指定和使用上更方便.
定义闭包的语法
闭包定义的语法如下:
Unable to find source-code formatter for language: groovy. Available languages are: xhtml, javascript, java, none, html, actionscript, xml, sql
{ [closureArguments->] statements }
在这里,[closureArguments->]是一个可选的参数列表,之间用逗号隔开,statements可以没有,可以有多个Groovy语句块.
参数列表与方法中的参数列表相似,并且可以有类型也可以没有类型.当一个参数表被指定后,"->"字符是必须的,用来隔开闭包体,"statements"部分由0个,1个或多个Groovy语句组成.
正确的闭包定义如下所示:
Unable to find source-code formatter for language: groovy. Available languages are: xhtml, javascript, java, none, html, actionscript, xml, sql
{ item++ }
{ println it}
{ ++it}
{ name -> println name }
{String x, int y -> println "hey $x the value is $y"}
{ reader ->
while (true) {
line = reader.readLine()
}
---》》待续......