在用Java編程時,大部分可執行的代碼要么被封裝在靜態類方法(static class methods)中,要么被封裝在實例方法(nstance methods)中(代碼
也可以被封裝在構造函數,初始化函數或初始化表達式中,但這些在這兒不重要).方法把代碼封裝在一對花括號里并給代碼段分配一個方法名.所有
這些方法必須定義在某種類型的類里面.例如,假設你要寫一個返回任意整數平方的方法,這個方法可以這樣寫:
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?=?4.
使用Groovy你也能完成上面的工作,不過在Groovy里面你不需要聲明任何類和方法.這一切由閉包來完成.閉包是封裝在花括號中的一條或幾條程
序語句.閉包和方法的最大區別在于閉包不需要類和方法名.下面的代碼將square()方法重寫為一個閉包.


{numberToSquare?->
?????numberToSquare?*?numberToSquare
};
正如你所看到的,除了不需要聲明類和分配給代碼方法名.然而要說明的是,上面的例子還不能用因為沒有使用閉包的方法.沒有標識(方法名)我
們怎么調用這個閉包呢?方法是:把創建的閉包賦給一個變量,那么你就可以使用這個變量作為閉包的標識來調用這個閉包.
//?初始化變量
int?x,?y;
x?=?2;

//?創佳閉包并把它賦給變量C

def?c?=?
{numberToSquare?->?numberToSquare?*?numberToSquare?}

//?使用變量C作為閉包的標識,?調用閉包
y?=?c.call(x);

//?y?=?4
閉包真正優越的地方是你可以創建閉包并把它賦給一個變量,并且可以像其他變量一樣在整個程序中傳遞.剛開始,你可能覺得這沒什么,幾乎毫
無用處,但是隨著你學習的深入,你會發現在Groovy里閉包無處不在.
舉個例子,我們用Groovy來擴展java.util.Vector類.我們添加一個方法到Vector類里,這個方法允許你應用閉包操作向量中的所有成員.我們新建
一個類GVector如下,
package
?example;


public
?
class
?GVector?
extends
?java.util.Vector?
{


??
public
?GVector()
{
??????
super
();
??}
??
public
?
void
?apply(?c?)
{

?????
for
?(i?in?
0
..
<
size())
{
????????
this
[i]?
=
?c(
this
[i]);
?????}
??}
}
apply()方法獲得一個閉包作為輸入參數,對于GVector中的每一個元素,閉包被調用傳遞這個元素,返回的結果值用來替換這個元素.這個思想就
是你可以使用閉包來修改GVector中的內容,這個閉包必須能夠獲取元素并把它轉換成別的什么.
現在我們就可以調用apply()方法了.你可以傳遞任意你需要的閉包給apply().例如我們新建一個GVector,設置幾個元素,然后將這些元素傳遞給
我們上面創建的那個能計算整數平方的閉包.
example.GVector?gVect?
=
?
new
?example.GVector();
gVect.add(
2
);
gVect.add(
3
);
gVect.add(
4
);


c?
=
?
{numberToSquare?
->
?numberToSquare?
*
?numberToSquare;}
gVect.apply(c);

//
?GVector中的所有元素全部被平方了.
由于apply()中的閉包可以是任意的,因此你可以把任何閉包傳遞給apply().例如使用下面的這個閉包簡單地把傳遞給它的元素打印出來.
example.GVector?gVect?=?new?example.GVector();
gVect.add(2);
gVect.add(3);
gVect.add(4);


c2?=?
{value?->?println(value);}

gVect.apply(c2);

//?GVector中的元素全部被打印出來.
假設你已經定義并編譯了GVector這個類,那么當你運行上面的腳本時,將得到下面的結果:
C:/>?groovy?myscript.groovy
4
9
16
C:/>
除了把閉包賦值給變量,你也可以直接把它聲明為方法的參數.例如,上面的代碼可以重寫為如下形式:
example.GVector?gVect?=?new?example.GVector();
gVect.add(2);
gVect.add(3);
gVect.add(4);


gVect.apply?
{value?->?println(value);}

//?GVector中的元素全部被打印出來.
這段代碼的功能和前面的功能一樣,只不過閉包被直接定義為apply()方法的參數.
閉包VS代碼段
閉包看上去就像正規的Java或Groovy代碼段,但是實際上他們并不相同.正規代碼段里的代碼一旦遇到就由虛擬機來執行,閉包中花括號里的代
碼直到call()被調用時才被執行.上面的例子中,閉包在程序行中定義,但是當時并不執行.只有閉包明確的調用call()時才會被執行.這是閉包和
代碼段的重要區別.也許他們看上去很像,但事實上兩者不同.正規的Java或Groovy代碼當遇到時就執行,;而閉包當且僅當call()被調用時才被
執行.?
????????????to be continue...
posted on 2006-04-26 17:05
學二的貓 閱讀(2546)
評論(4) 編輯 收藏 所屬分類:
Groovy