Unmi 學(xué)習(xí) Groovy 之閉包收藏| 舊一篇: Unmi 學(xué)習(xí) Groovy 之正則表達(dá)式一. 認(rèn)識閉包 將代碼塊作為方法參數(shù)進(jìn)行傳遞,這種機(jī)制就叫做閉包。閉包可以引用在創(chuàng)建閉包的范圍中可見的變量。最近關(guān)于閉包的討論也比較多,閉包能使語言更具靈動(dòng)性,在動(dòng)態(tài)腳本語言中較廣泛的支持,如 Perl、Python、Ruby、JavaScript,還有我們的 Groovy。 有些語言能把函數(shù)作為參數(shù)傳遞,如 JavaScript 的回調(diào)函數(shù),Python,甚至是 C++ 的函數(shù)指針。而 Java 在這方面又略遜一籌,需搬動(dòng)一個(gè)匿名的內(nèi)部類來實(shí)現(xiàn)類似的功能,內(nèi)部類只能訪問外部聲明為 final 的變量。不過有呼聲要在 Java SE 7 中增加閉包特性,讓我們試目以待吧。 Groovy 這回大概是從 Ruby 那兒偷得閉包的語法。前面說這么多,其實(shí)你看到了就會(huì)發(fā)現(xiàn),其實(shí)閉包很簡單的,不信,請看:
用大括號括起來的,給它一個(gè)名字 logo 的那段就是一個(gè)閉包(有點(diǎn)像 Java 中的語句塊);閉包可以通過執(zhí)行它的 call() 方法調(diào)用,或者直接把它當(dāng)作一個(gè)常規(guī)方法對待。閉包也可以沒有名字,比如下面要講的集合方法中用的閉包。
閉包可以有參數(shù)。如果是一個(gè)參數(shù)的話,該參數(shù)就直接映射到名為 it 的變量,如:
如果是多個(gè)參數(shù)的閉包,則在閉包中用 "->" 把參數(shù)列表和實(shí)現(xiàn)隔開,如:(當(dāng)然一個(gè)參數(shù)也可以這么方式定義的)
我看到這里,怎么越來越覺得閉包那么像 C/C++ 中的宏定義呢? 調(diào)用閉包時(shí),如果參數(shù)數(shù)量不對會(huì)拋出 IncorrectClosureArgumentException;不過對于一個(gè)參數(shù)的閉包,可以少傳但不能多傳參數(shù),不傳參數(shù)時(shí),閉包認(rèn)為 it 為 null。
閉包在實(shí)現(xiàn)上是擴(kuò)展自 groovy.lang.Closure 類,因?yàn)樗鼈兪穷?,所以可以作為參?shù)傳遞給其他的方法,下面就來看一個(gè)例子:
輸出為: Action occured: Status changed 上面這種用法可用在事件觸發(fā)、回調(diào)操作或策略模式中。
在 Groovy 中閉包可以訪問創(chuàng)建它的上下文中定義的變量,可在閉包中修改;而且閉包內(nèi)部定義的變量在周圍的上下文中也是可見的??慈缦麓a片斷:
執(zhí)行的結(jié)果是: 0.3
當(dāng)閉包與集合整合時(shí),它們展現(xiàn)了真正的威力。Groovy 中的 List、Map、String、和 Range 都有接受閉包參數(shù)的額外方法,譬如字符串也是字符的集合,也可以這么用。 涉及到的集合操作有 each、collect、inject、find、findAll、every、any。下面以例子來幫助理解這些方法的使用。
注意:上面的閉包傳給方法,如果是在 GroovyShell 中逐行敲入代碼時(shí),起始花括號"{" 必須與調(diào)用方法在同一行上,比如說寫成下面的方式就有問題:
然而如果你想要在單獨(dú)一行上指定起始花括號,可以使用下語法(調(diào)用方法后加個(gè)圓括號):
要是寫在 .groovy 文件中或是在 GroovyConsole 中不受這個(gè)限制,但是為規(guī)范和不致?lián)Q個(gè)環(huán)境又出錯(cuò),還是應(yīng)該讓起起始花括號"{" 與調(diào)用方法在同一行。 其實(shí)怎么去理解這種要求呢?主要是兩點(diǎn): 其一是為什么我們通常不寫這個(gè)圓括呢?那是 Groovy 允許方法調(diào)用時(shí)省略圓括號 還有就是在 GroovyShell 下,如果輸完方法名,如 each,然后馬上回車,就報(bào)錯(cuò) ERROR groovy.lang.MissingPropertyException: Exception evaluating property 'each' for java.util.ArrayList, Reason: groovy 只有方法名后面加個(gè)圓括號,它才知道是參數(shù)列表開始,直至匹配的右圓括號結(jié)束,或是加了花括,它也知道是一個(gè)閉包的開始,直到匹配的花括號結(jié)束。 1) collect() 方法利用指定的閉包轉(zhuǎn)換集合的元素
2) inject() 方法,可將前一次的迭代的結(jié)果傳遞給下一次迭代,請看例子:
輸出為: Previous: 0 - Current: 1 在當(dāng)前迭代中能知道上一次所迭代的值。inject 接受兩個(gè)參數(shù),第一次迭代中使用的注入值,和將要使用的閉包。這個(gè)閉包也必須定義兩個(gè)參數(shù),分別為上次迭代的注入值和當(dāng)前的元素。注意在閉包中必須返回下次迭代中注入的值。否則,就會(huì)假設(shè)為 null。 為了現(xiàn)好的理解發(fā)這個(gè)注入語法,我們將上述例子分開來寫成如下:
3) find() 方法找到符合閉包中所定義條件的第一次出現(xiàn)的元素,找不到則返回 null
4) findAll() 方法是返回所有符合閉包中所定義條件的元素所組成的集合
5) every() 方法檢查集合中是否每一個(gè)元素都符合閉包中指定的條件,是則返回 true,否則為 false
6) any() 方法則檢查集合中是否有一個(gè)元素符合閉包中指定的條件,有則返回 true,否則為 false
|
|