Groovy預覽--閉包


1.Groovy 中的閉包

Java的一些不足可以通過使用groovy的閉包很好的解決,通過下面這個例子來看看使用閉包的優勢:
在Java中遍歷一個集合的方法是使用迭代,就像下面這樣:

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 集合類型中的每個值上被調用。
在較高層面上,{} 中的代碼會執行三次,從而生成如圖所示的輸出。

Groovy
Java
Ruby

2聲明閉包

  迄今為止,我們已經使用了閉包的簡單語法:在一個方法調用的后面,放置閉包代碼在一對花括號里,閉包的參數和代碼通過(->)進行分隔。

  2.1簡單的聲明方式

  下圖中顯示了閉包語法的簡單方式和一個新的特性,當只有一個參數傳遞的時候,這個參數是可選的,魔術變量it代替了聲明

log=''
(1..10).each{counter -> log += counter }
println log  //12345678910


log=''
(1..10).each{log += it }
println log  //12345678910

  上面兩個閉包聲明是等價的,注意,不像counter,魔術變量it是不需要聲明的。

  2.2 使用賦值的方式聲明閉包

  第二種聲明閉包的方式是直接將它賦值給一個變量

def printer={ line -> println line}

閉包聲明在花括號中,並且賦給了printer變量

通過方法的返回值也是一種閉包的聲明方式

def Closure getPrinter(){
    return {line -> println line}
}

花括號指明構建了一個新的閉包對象,這個對象通過方法的調用返回

  2.3引用一個方法作為閉包

  第三種聲明閉包的方式是重用已有的聲明:一個方法。方法有一個方法體,可選的返回值,能夠接受參數,並且能夠被調用,於grooovy的閉包的相似性顯而易見,因此groovy可以重用你已經在方法中存在的代碼作為一個閉包,引用一個方法作為閉包使用reference.&操作符, reference是閉包調用時使用的對象實例,正如一個一般的方法調用使用reference.someMethod().  

上圖顯示了閉包的調用方法。

下面代碼演示了方法閉包的使用

class MethodClosureSample{

    int limit
    
    MethodClosureSample(int limit){
        this.limit = limit
    }
    
    boolean validate(String value){
        return value.length() <= limit
    }
}

MethodClosureSample first = new MethodClosureSample(6)
MethodClosureSample second = new MethodClosureSample(4)

def firstClosure = first.&validate; //方法作為閉包

def words=['Hello','Synvata','I','Love','you']

println words.findAll(firstClosure)         //[Hello, I, Love, you]
println words.findAll(second.&validate)     //[I, Love, you]

3 比較

下面展示了創建和使用閉包的所有方式:使用簡單聲明、賦值變量和方法閉包

map=['a':1,'b':2,'c':3]
/*直接把閉包作為參數傳遞,這是常用的方式*/
map.each{key,value -> map[key] = value * 2 }
println map        //[a:2, b:4, c:6]

/*將閉包對象賦值給變量doubler*/
doubler={key,value -> map[key] = value * 2 }
map.each(doubler)
println map        //[a:4, b:8, c:12]

/*聲明一個普通的方法*/
def doubleMethod(entry){
   map[entry.key]=entry.value * 2
}

/*reference.&操作符引用方法作為一個閉包*/
doubler=this.&doubleMethod
println doubler    //org.codehaus.groovy.runtime.MethodClosure@3fb547
map.each(doubler)
println map        //[a:8, b:16, c:24]

 4 調用閉包

假設有一個引用x指向一個閉包,我們能通過x.call()來調用閉包,或者簡單的x()

def col={println 'Hello, Groovy'}
col();        //Hello, Groovy
col.call()    //Hello, Groovy

現在,我們來試試更復雜的一些東西,從一個方法的內部調用閉包

def benchmark(repeat,Closure worker){
    start=System.currentTimeMillis()
    repeat.times{worker(it)}
    stop=System.currentTimeMillis()
    return stop-start
}

slow=benchmark(1000){ (int)it / 2 }
fast=benchmark(1000){ it.intdiv(2) }
println slow
println fast

benchmark中我們把閉包作為最后一個參數,這樣在調用該方法的時候就可以使用閉包的簡單語法聲明benchmark(){Closure}。方法參數中Closure聲明了閉包的類型,該聲明是可選的。repeat.times{worker(it)}根據repeat參數重復的調用閉包,並把當前重復的次數傳入閉包


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM