實(shí)戰(zhàn) Groovy: for each 剖析(轉(zhuǎn)載)

          迭代是編程的基礎(chǔ)。您經(jīng)常會(huì)遇到需要進(jìn)行逐項(xiàng)遍歷的內(nèi)容,比如 ListFile 和 JDBC ResultSet。Java 語(yǔ)言幾乎總是提供了某種方法幫助您逐項(xiàng)遍歷所需的內(nèi)容,但令人沮喪的是,它并沒有給出一種標(biāo)準(zhǔn)方法。Groovy 的迭代方法非常實(shí)用,在這一點(diǎn)上,Groovy 編程與 Java 編程截然不同。通過一些代碼示例,本文將介紹 Groovy 的萬(wàn)能的 each() 方法,從而將 Java 語(yǔ)言的那些迭代怪癖拋在腦后。

          Java 迭代策略

          假設(shè)您有一個(gè) Java 編程語(yǔ)言的 java.util.List。清單 1 展示了在 Java 語(yǔ)言中如何使用編程實(shí)現(xiàn)迭代:


          清單 1. Java 列表迭代
          import java.util.*;  
          public class ListTest{
           public static void main(String[] args){
           List<String> list = new ArrayList<String>();
           list.add("Java");
           list.add("Groovy");
           list.add("JavaScript");
           for(Iterator<String> i = list.iterator(); i.hasNext();){
           String language = i.next();
           System.out.println("I know " + language);
           }
           }
           }

          由于提供了大部分集合類都可以共享的 java.lang.Iterable 接口,您可以使用相同的方法遍歷 java.util.Setjava.util.Queue

          關(guān)于本系列

          Groovy 是一款運(yùn)行在 Java 平臺(tái)之上的現(xiàn)代編程語(yǔ)言。它能夠與現(xiàn)有 Java 代碼無(wú)縫集成,同時(shí)引入了閉包和元編程等出色的新特性。簡(jiǎn)而言之,Groovy 類似于 21 世紀(jì)的 Java 語(yǔ)言。

          如果要將新工具集成到開發(fā)工具箱中,最關(guān)鍵的是理解什么時(shí)候需要使用它以及什么時(shí)候不適合使用它。Groovy 可以變得非常強(qiáng)大,但前提是它被適當(dāng)?shù)貞?yīng)用到合適的場(chǎng)景中。因此, 實(shí)戰(zhàn) Groovy 系列旨在展示 Groovy 的實(shí)際使用,以及何時(shí)和如何成功應(yīng)用它。

          現(xiàn)在,假設(shè)該語(yǔ)言存儲(chǔ)在 java.util.Map 中。在編譯時(shí),嘗試對(duì) Map 獲取 Iterator 會(huì)導(dǎo)致失敗 — Map 并沒有實(shí)現(xiàn) Iterable 接口。幸運(yùn)的是,可以調(diào)用 map.keySet() 返回一個(gè) Set,然后就可以繼續(xù)處理。這些小差異可能會(huì)影響您的速度,但不會(huì)妨礙您的前進(jìn)。需要注意的是,ListSetQueue 實(shí)現(xiàn)了 Iterable,但是 Map 沒有 — 即使它們位于相同的 java.util 包中。

          現(xiàn)在假設(shè)該語(yǔ)言存在于 String 數(shù)組中。數(shù)組是一種數(shù)據(jù)結(jié)構(gòu),而不是類。不能對(duì) String 數(shù)組調(diào)用 .iterator(),因此必須使用稍微不同的迭代策略。您再一次受到阻礙,但可以使用如清單 2 所示的方法解決問題:


          清單 2. Java 數(shù)組迭代
          public class ArrayTest{
           public static void main(String[] args){
           String[] list = {"Java", "Groovy", "JavaScript"};
           for(int i = 0; i < list.length; i++){
           String language = list[i];
           System.out.println("I know " + language);
           }
           }
           }

          但是等一下 — 使用 Java 5 引入的 for-each 語(yǔ)法怎么樣?它可以處理任何實(shí)現(xiàn) Iterable 的類和數(shù)組,如清單 3 所示:


          清單 3. Java 語(yǔ)言的 for-each 迭代
          import java.util.*;
           public class MixedTest{
           public static void main(String[] args){
           List<String> list = new ArrayList<String>();
           list.add("Java");
           list.add("Groovy");
           list.add("JavaScript");
           for(String language: list){
           System.out.println("I know " + language);
           }
          String[] list2 = {"Java", "Groovy", "JavaScript"};
           for(String language: list2){
           System.out.println("I know " + language);
           }
           }
           }

          因此,您可以使用相同的方法遍歷數(shù)組和集合(Map 除外)。但是如果語(yǔ)言存儲(chǔ)在 java.io.File,那該怎么辦?如果存儲(chǔ)在 JDBC ResultSet,或者存儲(chǔ)在 XML 文檔、java.util.StringTokenizer 中呢?面對(duì)每一種情況,必須使用一種稍有不同的迭代策略。這樣做并不是有什么特殊目的 — 而是因?yàn)椴煌?API 是由不同的開發(fā)人員在不同的時(shí)期開發(fā)的 — 但事實(shí)是,您必須了解 6 個(gè) Java 迭代策略,特別是使用這些策略的特殊情況。

          Eric S. Raymond 在他的 The Art of Unix Programming 一書中解釋了 “最少意外原則”。他寫道,“要設(shè)計(jì)可用的接口,最好不要設(shè)計(jì)全新的接口模型。新鮮的東西總是難以入門;會(huì)為用戶帶來(lái)學(xué)習(xí)的負(fù)擔(dān),因此應(yīng)當(dāng)盡量減少新內(nèi) 容。”Groovy 對(duì)迭代的態(tài)度正是采納了 Raymond 的觀點(diǎn)。在 Groovy 中遍歷幾乎任何結(jié)構(gòu)時(shí),您只需要使用 each() 這一種方法。


          Groovy 中的列表迭代

          首先,我將 清單 3 中的 List 重構(gòu)為 Groovy。在這里,只需要直接對(duì)列表調(diào)用 each() 方法并傳遞一個(gè)閉包,而不是將 List 轉(zhuǎn)換成 for 循環(huán)(順便提一句,這樣做并不是特別具有面向?qū)ο蟮奶卣鳎皇菃幔?

          創(chuàng)建一個(gè)名為 listTest.groovy 的文件并添加清單 4 中的代碼:


          清單 4. Groovy 列表迭代
          def list = ["Java", "Groovy", "JavaScript"] list.each{language->   println language } 

          清單 4 中的第一行是 Groovy 用于構(gòu)建 java.util.ArrayList 的便捷語(yǔ)法。可以將 println list.class 添加到此腳本來(lái)驗(yàn)證這一點(diǎn)。接下來(lái),只需對(duì)列表調(diào)用 each(),并在閉包體內(nèi)輸出 language 變量。在閉包的開始處使用 language-> 語(yǔ)句命名 language 變量。如果沒有提供變量名,Groovy 提供了一個(gè)默認(rèn)名稱 it。在命令行提示符中輸入 groovy listTest 運(yùn)行 listTest.groovy。

          清單 5 是經(jīng)過簡(jiǎn)化的 清單 4 代碼版本:


          清單 5. 使用 Groovy 的 it 變量的迭代
           // shorter, using the default it variable 
          def list = ["Java", "Groovy", "JavaScript"]
           list.each{ println it }
           // shorter still, using an anonymous
          list ["Java", "Groovy", "JavaScript"].each{ println it }

          Groovy 允許您對(duì)數(shù)組和 List 交替使用 each() 方法。為了將 ArrayList 改為 String 數(shù)組,必須將 as String[] 添加到行末,如清單 6 所示:


          清單 6. Groovy 數(shù)組迭代
          def list = ["Java", "Groovy", "JavaScript"] as String[] list.each{println it} 

          在 Groovy 中普遍使用 each() 方法,并且 getter 語(yǔ)法非常便捷(getClass()class 是相同的調(diào)用),這使您能夠編寫既簡(jiǎn)潔又富有表達(dá)性的代碼。例如,假設(shè)您希望利用反射顯示給定類的所有公共方法。清單 7 展示了這個(gè)例子:


          清單 7. Groovy 反射
          def s = "Hello World"
           println s
          println s.class
           s.class.methods.each{println it}
           //output:
          $ groovy reflectionTest.groovy
           Hello World
           class java.lang.String
           public int java.lang.String.hashCode()
           public volatile int java.lang.String.compareTo(java.lang.Object)
           public int java.lang.String.compareTo(java.lang.String)
           public boolean java.lang.String.equals(java.lang.Object) ...

          腳本的最后一行調(diào)用 getClass() 方法。java.lang.Class 提供了一個(gè) getMethods() 方法,后者返回一個(gè)數(shù)組。通過將這些操作串連起來(lái)并對(duì) Method 的結(jié)果數(shù)組調(diào)用 each(),您只使用了一行代碼就完成了大量工作。

          但是,與 Java for-each 語(yǔ)句不同的是,萬(wàn)能的 each() 方法并不僅限于 List 和數(shù)組。在 Java 語(yǔ)言中,故事到此結(jié)束。然而,在 Groovy 中,故事才剛剛開始。

          Map 迭代

          從前文可以看到,在 Java 語(yǔ)言中,無(wú)法直接迭代 Map。在 Groovy 中,這完全不是問題,如清單 8 所示:


          清單 8. Groovy map 迭代
          def map = ["Java":"server", "Groovy":"server", "JavaScript":"web"] map.each{ println it } 

          要處理名稱/值對(duì),可以使用隱式的 getKey()getValue() 方法,或在包的開頭部分顯式地命名變量,如清單 9 所示:


          清單 9. 從 map 獲得鍵和值
          def map = ["Java":"server", "Groovy":"server", "JavaScript":"web"]
           map.each{
           println it.key
           println it.value
           }
          map.each{k,v->
           println k
           println v
           }

          可以看到,迭代 Map 和迭代其它任何集合一樣自然。

          在繼續(xù)研究下一個(gè)迭代例子前,應(yīng)當(dāng)了解 Groovy 中有關(guān) Map 的另一個(gè)語(yǔ)法。與在 Java 語(yǔ)言中調(diào)用 map.get("Java") 不一樣,可以簡(jiǎn)化對(duì) map.Java 的調(diào)用,如清單 10 所示:


          清單 10. 獲得 map 值
          def map = ["Java":"server", "Groovy":"server", "JavaScript":"web"]
           //identical results
           println map.get("Java")
           println map.Java

          不可否認(rèn),Groovy 針對(duì) Map 的這種便捷語(yǔ)法非常酷,但這也是在對(duì) Map 使用反射時(shí)引起一些常見問題的原因。對(duì) list.class 的調(diào)用將生成 java.util.ArrayList,而調(diào)用 map.class 返回 null。這是因?yàn)楂@得 map 元素的便捷方法覆蓋了實(shí)際的 getter 調(diào)用。Map 中的元素都不具有 class 鍵,因此調(diào)用實(shí)際會(huì)返回 null,如清單 11 的示例所示:


          清單 11. Groovy map 和 null
          def list = ["Java", "Groovy", "JavaScript"]
           println list.class
           // java.util.ArrayList
           def map = ["Java":"server", "Groovy":"server", "JavaScript":"web"]
           println map.class
           // null
           map.class = "I am a map element"
           println map.class
           // I am a map element
           println map.getClass()
           // class
           java.util.LinkedHashMap

          這是 Groovy 比較罕見的打破 “最少意外原則” 的情況,但是由于從 map 獲取元素要比使用反射更加常見,因此我可以接受這一例外。


          String 迭代

          現(xiàn)在您已經(jīng)熟悉 each() 方法了,它可以出現(xiàn)在所有相關(guān)的位置。假設(shè)您希望迭代一個(gè) String,并且是逐一迭代字符,那么馬上可以使用 each() 方法。如清單 12 所示:


          清單 12. String 迭代
          def name = "Jane Smith" name.each{letter->
           println letter
           }

          這提供了所有的可能性,比如使用下劃線替代所有空格,如清單 13 所示:


          清單 13. 使用下劃線替代空格

          def name = "Jane Smith"
           println "replace spaces"
          name.each{
           if(it == " "){
           print "_"
           }else{
           print it
           }
           }
           // output Jane_Smith

          當(dāng)然,在替換一個(gè)單個(gè)字母時(shí),Groovy 提供了一個(gè)更加簡(jiǎn)潔的替換方法。您可以將清單 13 中的所有代碼合并為一行代碼:"Jane Smith".replace(" ", "_")。但是對(duì)于更復(fù)雜的 String 操作,each() 方法是最佳選擇。


          Range 迭代

          Groovy 提供了原生的 Range 類型,可以直接迭代。使用兩個(gè)點(diǎn)分隔的所有內(nèi)容(比如 1..10)都是一個(gè) Range。清單 14 展示了這個(gè)例子:


          清單 14. Range 迭代
          def range = 5..10 range.each{
           println it
           }
           //output: 5 6 7 8 9 10

          Range 不局限于簡(jiǎn)單的 Integer。考慮清單 15 在的代碼,其中迭代 DateRange


          清單 15. Date 迭代
          def today = new Date()
           def nextWeek = today + 7
           (today..nextWeek).each{
           println it
           }
          //output: Thu Mar 12 04:49:35 MDT 2009
           Fri Mar 13 04:49:35 MDT 2009
          Sat Mar 14 04:49:35 MDT 2009
          Sun Mar 15 04:49:35 MDT 2009
          Mon Mar 16 04:49:35 MDT 2009
          Tue Mar 17 04:49:35 MDT 2009
          Wed Mar 18 04:49:35 MDT 2009
          Thu Mar 19 04:49:35 MDT 2009

          可以看到,each() 準(zhǔn)確地出現(xiàn)在您所期望的位置。Java 語(yǔ)言缺乏原生的 Range 類型,但是提供了一個(gè)類似地概念,采取 enum 的形式。毫不奇怪,在這里 each() 仍然派得上用場(chǎng)。


          Enumeration 類型

          Java enum 是按照特定順序保存的隨意的值集合。清單 16 展示了 each() 方法如何自然地配合 enum,就好象它在處理 Range 操作符一樣:


          清單 16. enum 迭代
          enum DAY{
           MONDAY, TUESDAY, WEDNESDAY, THURSDAY,
           FRIDAY, SATURDAY, SUNDAY
           }
           DAY.each{
           println it
           }
           (DAY.MONDAY..DAY.FRIDAY).each{
           println it
           }

          在 Groovy 中,有些情況下,each() 這個(gè)名稱遠(yuǎn)未能表達(dá)它的強(qiáng)大功能。在下面的例子中,將看到使用特定于所用上下文的方法對(duì) each() 方法進(jìn)行修飾。Groovy eachRow() 方法就是一個(gè)很好的例子。


          SQL 迭代

          在處理關(guān)系數(shù)據(jù)庫(kù)表時(shí),經(jīng)常會(huì)說(shuō) “我需要針對(duì)表中的每一行執(zhí)行操作”。比較一下前面的例子。您很可能會(huì)說(shuō) “我需要對(duì)列表中的每一種語(yǔ)言執(zhí)行一些操作”。根據(jù)這個(gè)道理,groovy.sql.Sql 對(duì)象提供了一個(gè) eachRow() 方法,如清單 17 所示:


          清單 17. ResultSet 迭代
          import groovy.sql.*
           def sql = Sql.newInstance(
           "jdbc:derby://localhost:1527/MyDbTest;create=true",
           "username",
           "password",
           "org.apache.derby.jdbc.ClientDriver")
           println("grab a specific field")
           sql.eachRow("select name from languages"){ row ->
           println row.name
           }
           println("grab all fields")
           sql.eachRow("select * from languages"){ row ->
           println("Name: ${row.name}")
           println("Version: ${row.version}")
           println("URL: ${row.url}\n")
           }

          該腳本的第一行代碼實(shí)例化了一個(gè)新的 Sql 對(duì)象:設(shè)置 JDBC 連接字符串、用戶名、密碼和 JDBC 驅(qū)動(dòng)器類。這時(shí),可以調(diào)用 eachRow() 方法,傳遞 SQL select 語(yǔ)句作為一個(gè)方法參數(shù)。在閉包內(nèi)部,可以引用列名(nameversionurl),就好像實(shí)際存在 getName()getVersion()getUrl() 方法一樣。

          這顯然要比 Java 語(yǔ)言中的等效方法更加清晰。在 Java 中,必須創(chuàng)建單獨(dú)的 DriverManagerConnectionStatementJDBCResultSet,然后必須在嵌套的 try/catch/finally 塊中將它們?nèi)壳宄?

          對(duì)于 Sql 對(duì)象,您會(huì)認(rèn)為 each()eachRow() 都是一個(gè)合理的方法名。但是在接下來(lái)的示例中,我想您會(huì)認(rèn)為 each() 這個(gè)名稱并不能充分表達(dá)它的功能。


          文件迭代

          我從未想過使用原始的 Java 代碼逐行遍歷 java.io.File。當(dāng)我完成了所有的嵌套的 BufferedReaderFileReader 后(更別提每個(gè)流程末尾的所有異常處理),我已經(jīng)忘記最初的目的是什么。

          清單 18 展示了使用 Java 語(yǔ)言完成的整個(gè)過程:


          清單 18. Java 文件迭代
          import java.io.BufferedReader;
           import java.io.FileNotFoundException;
           import java.io.FileReader; import java.io.IOException;
           public class WalkFile {
           public static void main(String[] args) {
           BufferedReader br = null;
           try {
           br = new BufferedReader(new FileReader("languages.txt"));
           String line = null;
           while((line = br.readLine()) != null) {
           System.out.println("I know " + line);
           }
           }
           catch(FileNotFoundException e) {
           e.printStackTrace();
           }
           catch(IOException e) {
           e.printStackTrace();
           }
           finally {
           if(br != null) {
           try {
           br.close();
           }
          catch(IOException e) {
           e.printStackTrace();
           }
           }
           }
           }
           }

          清單 19 展示了 Groovy 中的等效過程:


          清單 19. Groovy 文件迭代
          def f = new File("languages.txt") f.eachLine{language->
           println "I know ${language}"
          }

          這正是 Groovy 的簡(jiǎn)潔性真正擅長(zhǎng)的方面。現(xiàn)在,我希望您了解為什么我將 Groovy 稱為 “Java 程序員的 DSL”。

          注意,我在 Groovy 和 Java 語(yǔ)言中同時(shí)處理同一個(gè) java.io.File 類。如果該文件不存在,那么 Groovy 代碼將拋出和 Java 代碼相同的 FileNotFoundException 異常。區(qū)別在于,Groovy 沒有已檢測(cè)的異常。在 try/catch/finally 塊中封裝 eachLine() 結(jié)構(gòu)是我自己的愛好 — 而不是一項(xiàng)語(yǔ)言需求。對(duì)于一個(gè)簡(jiǎn)單的命令行腳本中,我欣賞 清單 19 中的代碼的簡(jiǎn)潔性。如果我在運(yùn)行應(yīng)用服務(wù)的同時(shí)執(zhí)行相同的迭代,我不能對(duì)這些異常坐視不管。我將在與 Java 版本相同的 try/catch 塊中封裝 eachLine() 塊。

          File 類對(duì) each() 方法進(jìn)行了一些修改。其中之一就是 splitEachLine(String separator, Closure closure)。這意味著您不僅可以逐行遍歷文件,同時(shí)還可以將它分為不同的標(biāo)記。清單 20 展示了一個(gè)例子:


          清單 20. 分解文件的每一行
          // languages.txt
           // notice the space between the language and the version Java 1.5 Groovy 1.6 JavaScript 1.x
           // splitTest.groovy
          def f = new File("languages.txt")
           f.splitEachLine(" "){words->
           words.each{ println it
           }
           }
          // output Java 1.5 Groovy 1.6 JavaScript 1.x

          如果處理的是二進(jìn)制文件,Groovy 還提供了一個(gè) eachByte() 方法。

          當(dāng)然,Java 語(yǔ)言中的 File 并不總是一個(gè)文件 — 有時(shí)是一個(gè)目錄。Groovy 還提供了一些 each() 修改以處理子目錄。


          目錄迭代

          使用 Groovy 代替 shell 腳本(或批處理腳本)非常容易,因?yàn)槟軌蚍奖愕卦L問文件系統(tǒng)。要獲得當(dāng)前目錄的目錄列表,參見清單 21:


          清單 21. 目錄迭代
          def dir = new File(".") dir.eachFile{file->
           println file
           }

          eachFile() 方法同時(shí)返回了文件和子目錄。使用 Java 語(yǔ)言的 isFile()isDirectory() 方法,可以完成更復(fù)雜的事情。清單 22 展示了一個(gè)例子:


          清單 22. 分離文件和目錄
          def dir = new File(".") dir.eachFile{file->
           if(file.isFile()){
           println "FILE: ${file}"
           }else if(file.isDirectory()){
           println "DIR: ${file}"
           }else{
           println "Uh, I'm not sure what it is..."
           }
           }

          由于兩種 Java 方法都返回 boolean 值,可以在代碼中添加一個(gè) Java 三元操作符。清單 23 展示了一個(gè)例子:


          清單 23. 三元操作符
          def dir = new File(".")
           dir.eachFile{file->
           println file.isDirectory() ? "DIR: ${file}" : "FILE: ${file}"
           }

          如果只對(duì)目錄有興趣,那么可以使用 eachDir() 而不是 eachFile()。還提供了 eachDirMatch()eachDirRecurse() 方法。

          可以看到,對(duì) File 僅使用 each() 方法并不能提供足夠的含義。典型 each() 方法的語(yǔ)義保存在 File 中,但是方法名更具有描述性,從而提供更多有關(guān)這個(gè)高級(jí)功能的信息。


          URL 迭代

          理解了如何遍歷 File 后,可以使用相同的原則遍歷 HTTP 請(qǐng)求的響應(yīng)。Groovy 為 java.net.URL 提供了一個(gè)方便的(和熟悉的)eachLine() 方法。

          例如,清單 24 將逐行遍歷 ibm.com 主頁(yè)的 HTML:


          清單 24. URL 迭代
          def url = new URL("http://www.ibm.com")
           url.eachLine{line->
           println line
           }

          當(dāng)然,如果這就是您的目的的話,Groovy 提供了一個(gè)只包含一行代碼的解決辦法,這主要?dú)w功于 toURL() 方法,它被添加到所有 Strings"http://www.ibm.com".toURL().eachLine{ println it }

          但是,如果希望對(duì) HTTP 響應(yīng)執(zhí)行一些更有用的操作,該怎么辦呢?具體來(lái)講,如果發(fā)出的請(qǐng)求指向一個(gè) RESTful Web 服務(wù),而該服務(wù)包含您要解析的 XML,該怎么做呢?each() 方法將在這種情況下提供幫助。


          XML 迭代

          您已經(jīng)了解了如何對(duì)文件和 URL 使用 eachLine() 方法。XML 給出了一個(gè)稍微有些不同的問題 — 與逐行遍歷 XML 文檔相比,您可能更希望對(duì)逐個(gè)元素進(jìn)行遍歷。

          例如,假設(shè)您的語(yǔ)言列表存儲(chǔ)在名為 languages.xml 的文件中,如清單 25 所示:


          清單 25. languages.xml 文件
          <langs>
           <language>Java</language>
           <language>Groovy</language>
           <language>JavaScript</language>
           </langs>

          Groovy 提供了一個(gè) each() 方法,但是需要做一些修改。如果使用名為 XmlSlurper 的原生 Groovy 類解析 XML,那么可以使用 each() 遍歷元素。參見清單 26 所示的例子:


          清單 26. XML 迭代
          def langs = new XmlSlurper().parse("languages.xml")
           langs.language.each{
           println it
           }
           //output Java Groovy JavaScript

          langs.language.each 語(yǔ)句從名為 <language><langs> 提取所有元素。如果同時(shí)擁有 <format><server> 元素,它們將不會(huì)出現(xiàn)在 each() 方法的輸出中。

          如果覺得這還不夠的話,那么假設(shè)這個(gè) XML 是通過一個(gè) RESTful Web 服務(wù)的形式獲得,而不是文件系統(tǒng)中的文件。使用一個(gè) URL 替換文件的路徑,其余代碼仍然保持不變,如清單 27 所示:


          清單 27. Web 服務(wù)調(diào)用的 XML 迭代
          def langs = new XmlSlurper().parse("http://somewhere.com/languages")
           langs.language.each{
           println it
           }

          這真是個(gè)好方法,each() 方法在這里用得很好,不是嗎?


          結(jié)束語(yǔ)

          在使用 each() 方法的整個(gè)過程中,最妙的部分在于它只需要很少的工作就可以處理大量 Groovy 內(nèi)容。解了 each() 方法之后,Groovy 中的迭代就易如反掌了。正如 Raymond 所說(shuō),這正是關(guān)鍵所在。一旦了解了如何遍歷 List,那么很快就會(huì)掌握如何遍歷數(shù)組、MapStringRangeenum、SQL ResultSetFile、目錄和 URL,甚至是 XML 文檔的元素。

          本文的最后一個(gè)示例簡(jiǎn)單提到使用 XmlSlurper 實(shí)現(xiàn) XML 解析。在下一期文章中,我將繼續(xù)討論這個(gè)問題,并展示使用 Groovy 進(jìn)行 XML 解析有多么簡(jiǎn)單!您將看到 XmlParserXmlSlurper 的實(shí)際使用,并更好地了解 Groovy 為什么提供兩個(gè)類似但又略有不同的類實(shí)現(xiàn) XML 解析。到那時(shí),希望您能發(fā)現(xiàn) Groovy 的更多實(shí)際應(yīng)用。

          posted on 2011-08-04 11:50 小羅 閱讀(553) 評(píng)論(0)  編輯  收藏 所屬分類: groovy


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          <2011年8月>
          31123456
          78910111213
          14151617181920
          21222324252627
          28293031123
          45678910

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          相冊(cè)

          收藏夾

          Web Framework

          常上的技術(shù)網(wǎng)站

          查找資料的java網(wǎng)站

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 莫力| 苏尼特右旗| 三门峡市| 双柏县| 汝城县| 容城县| 奇台县| 清涧县| 枝江市| 泸西县| 佳木斯市| 正定县| 祁阳县| 尼木县| 班玛县| 甘泉县| 望都县| 子洲县| 武清区| 石家庄市| 虎林市| 武威市| 桃园县| 渝北区| 大连市| 通州区| 洪江市| 鄄城县| 杭锦后旗| 临猗县| 井冈山市| 承德县| 新丰县| 开化县| 通江县| 竹北市| 南开区| 延寿县| 确山县| 来凤县| 西华县|