Groovy探索之Gpath和List的結合 更加Groovy風格的程式碼

hivon發表於2009-03-24

                Groovy探索之Gpath和List的結合 更加Groovy風格的程式碼

 

 

在使用Groovy語言的日子裡,我常常都被一些Groovy的風格所驚喜著。如閉包、each等方法、Gpath、Map引數等等,等等。我不知道其他動態語言是否也具有這樣的一些風格,但起碼這些風格是區別於Java語言的風格。我是多年的Java程式設計師,遇到這些簡單、易懂的風格,難免會驚喜不已。

很多的Groovy語言風格我們很容易接受,如each方法,Gpath語句。

比如,我們有了如下的一個List物件:

 

      def list = [1,2,3,4]

 

我們在Groovy語言裡要遍歷這個list物件,我們肯定會輕鬆的使用下面的each方法:

 

      list.each{

         println it

      }

 

而不會使用下面的for迴圈:

 

      for(int it in list)

      {

         println it

      }

   

 

這些都是非常簡單和明瞭的,就像我們會使用了Gpath語句,誰還會使用對於Bean物件的屬性操作的"set"和"get"方法呢?

但是有一些Groovy語言風格的程式碼,卻不是那麼容易寫得出來,特別是對於我們這些Java程式設計師來說。

但是,我們一旦學會的那些Groovy語言風格的程式碼,卻會給我們帶來更大、更多的驚喜。而這些本文所要說到的。

正如標題所言,我們今天要說到的Groovy語言風格的程式碼,是結合了List物件的一些方法和Gpath語句的程式碼。

 

比如,我們有如下的一個Map物件,用來表示一些城市和她們所在的國家:

 

 

      def cities = ['Shanghai':'China','New York':'USA','Pairs':'France','Beijing':'China']

 

現在,我們想知道在這個Map物件中,所在國為中國的城市有哪些?在Java語言中,我們會毫不猶豫的寫出如下的程式碼:

 

      def citiesInChina = []

      cities.each{

         if(it.value=='China')

         {

             citiesInChina << it.key

         }

      }

     

      println citiesInChina

   

而在Groovy語言中,我們的具有Groovy語言風格的程式碼應該是如下的形式:

     

      def citiesInChina = cities.findAll{

         it.value == 'China'

      }.collect{it.key}

     

     

     

      println citiesInChina

   

從上面的程式碼,我們可以初步的看到集合方法和Gpath結合起來的程式碼風格的威力。但這還不是最經典的例子。

比如我們有如下的一些GroovyBean:

 

class Book {

   

    String name

   

    List authors

 

 

}

 

class Author {

   

    String name

   

    Address addr

 

 

 

}

 

class Address {

   

    String province

   

    String city

 

}

上面的GroovBean的層次結構有點複雜,簡單說來就是:一本書有一個或多個作者,每一個作者又都有屬於自己的地址。現在,我們有如下的一個初始化資料:

      

       def addr1 = new Address(province:'Guangdong',city:'Shenzhen')

       def addr2 = new Address(province:'Gunagdong',city:'Guangzhou')

       def addr3 = new Address(province:'Hunan',city:'Changsha')

       def addr4 = new Address(province:'Hubei',city:'Wuhan')

      

       def books = [new Book(name:'A glance at Java',authors:[new Author(name:'Tom',addr:addr1)]),

                    new Book(name:'Deep into Groovy',authors:[new Author(name:'Tom',addr:addr1),new Author(name:'Mike',addr:addr3)]),

                    new Book(name:'A compare of Struts and Grails',authors:[new Author(name:'Wallace',addr:addr4),new Author(name:'Bill',addr:addr2)]),

                    new Book(name:'learning from Groovy to Grails',authors:[new Author(name:'Wallace',addr:addr3)])]

   

在上面的資料中,books變數是由多本書組成,而那些書,有的有一個作者,有的有多個作者,但每個作者都有他自己的地址。

現在,我們想找出作者是"Tom"的書籍的書名。在Java語言中,我們就會有如下形式的程式碼:

       def booksOfTom = []

      

       books.each{

           def book = it

           def aus = it.authors

          

           aus.each{au->

              if(au.name=='Tom') booksOfTom<<book.name

           }

       }

      

      

    println booksOfTom

 

但是,上面的需求,在Groovy語言中是如下風格的程式碼:

       def booksOfTom = books.grep{

           it.authors.any{it.name=='Tom'}

       }.name

    println booksOfTom

 

首先,對"books"使用"grep"方法,最後得到的結果應該是一個"Book"物件的集合,再對該集合取"name",在這裡,".name"相當於"*.name"。

在"grep"方法內部,"it.authors"取得了所有的作者,然後再通過"any"方法來遍歷作者名為"Tom"的"Book"物件。

這就是結合集合方法和Gpath的Groovy程式碼風格,開始學起來有一定的難度,但是理解之後,這種程式碼風格、這種方法十分好用。下面再舉一例。

比如,我們想取得作者是"Wallace"的作者所在的城市(這裡有重名的作者)。Java語言的編碼風格應該是這樣的:

       def citiesOfWallace = []

 

       books.each{

           def book = it

           def authors = it.authors

           authors.each{

              author->

                  if(author.name == 'Wallace')

                  {

                     def addr = author.addr

                     citiesOfWallace << addr.city

                  }

           }

       }

 

    println citiesOfWallace

 

但是Groovy語言卻會寫出如下風格的程式碼來:

 

       def citiesOfWallace = books.authors.flatten().grep{

           it.name == 'Wallace'

       }.addr.city

      

      

    println citiesOfWallace

 

"books.authors"的結果是一個集合物件,它裡面是由四個集合物件組成,這四個集合物件中的每一個集合物件都是由"Author"物件組成。因此對它們進行"flatten"方法,直接獲得一個集合物件,由"Author"物件組成。

然後再進行"Author"物件的"name"屬性是否為"Wallace"的匹配,匹配完成,得到一個由"Author"物件組成的集合物件。

最後進行取".addr.city",得到一個由"city"組成的集合。也就是需要的結果。

相關文章