Groovy介紹
- 是一種基於JVM的敏捷開發語言
- 結合了Python、Ruby、Smalltalk的許多強大特性
- Groovy可以與Java完美結合,而且可以使用Java所有的庫
Groovy特性
- 語法上支援動態型別,閉包等新一代語言特性
- 無縫整合所有已存在的Java類庫
- 即支援物件導向程式設計也支援程式導向程式設計
Groovy優勢
- 一種更加敏捷的程式語言
- 入門非常容易,但功能非常強大
- 即可以作為程式語言也可以作為指令碼語言
- 熟悉Java會非常容易掌握Groovy
Groovy基礎語法
1. Groovy中語句結束符可以使用“;”,也可以不使用;
2. Groovy中類、變數和方法,預設是public。
3. 輸出語句
// 1. 可以和Java一樣
class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello Groovy")
}
}
// 2. 直接輸出(兩種)
println "Hello Groovy"
println("Hello Groovy")
複製程式碼
4. Groovy中的變數
-
變數的型別:基本型別(java中的int/float/double/byte/char/long/short)和物件型別(String等) ,在Groovy中最終都是物件型別。
int x = 10 println x.class //結果為:class java.lang.Integer double y = 3.14 println y.class //結果為:class java.lang.Double 複製程式碼
由此可見,Groovy中的基本型別最終會被編譯器包裝成物件型別
-
變數的定義:強型別定義方式和弱型別def定義方式
def x1 = 10 def y1 = 3.14 def str1 = 'groovy str' x1 = 'grovvy def' println x1.class //class java.lang.Integer println y1.class //class java.math.BigDecimal println str1.class //class java.lang.String println x1.class //class java.lang.String 複製程式碼
強型別定義及定義的時候寫明變數的型別,而def則由編譯器自行推導變數的型別
強型別定義方式和弱型別def定義方式的選擇:
* 變數用於本類或者本模組而不會用於其它類或者其他模組,推薦使用def型別,這樣可以隨時動態的轉換為其它型別; * 變數要用於其它類或是其它模組,強烈建議使用強型別定義方式。使用強型別定義的方式不能動態轉換型別,才能使外界傳入或者呼叫的時候不會對於資料的型別產生疑惑,這樣就保證外界傳入的資料一定是我們想要的正確的型別的資料。 複製程式碼
5. 字串詳解
- 兩種字串:String(同Java中的String一樣)、GString
- 字串常用的三種定義方式
//1. 單引號定義的就是java中的String,內容即為''內的字串,並且不可更改 def str1 = 'a single string' println str1.class //class java.lang.String // 有特殊字元同樣的通過反斜槓轉義 def str2 = 'a single \'special\' string' //2. 三個單引號定義的是有格式的字串,會直接按照我們寫的格式進行輸出,而不用像Java中進行拼接 def trebleStr = '''line one line two line three ''' //3. 雙引號 def name = "Groovy" println name.class //class java.lang.String // 字串模板 def sayHello = "Hello $name" // 字串模板也可以是表示式 def sum = "the sum of 2 and 3 equals ${2 + 3}" 複製程式碼
- String方法來源
- java.lang.String原有的方法
- DefaultGroovyMethods:是Groovy對所有物件的一個擴充套件
- StringGroovyMethods:繼承自DefaultGroovyMethods,重寫了DefaultGroovyMethods中的許多方法,使這些方法更加適用於String使用。
- Groovy中的兩種字串,對於開發者都是字串,和之前正常定義即可。兩者之間的轉換都是編譯器完成的,開發者不關注這些。即便定義的是Java的String,可以使用GString的方法,最終的轉換都是編譯器完成。因此,String 和GString之間可以相互呼叫和傳遞,不需要考慮它們之間的轉換問題。
- 字串方法
//字串填充: // 1. center(Number numberOfChars,CharSequence padding) ,將字串作為中心進行填充 // 當numberOfChars小於或等於str本身的長度時,不進行填充操作,大於則用pandding擴充套件至長度numberOfChars,從字串的右邊(尾)進行填充,再到左邊(頭) def str = "groovy" println str.center(8) //結果: groovy ,不傳padding代表以空格填充 println str.center(5,"a") //結果: groovy println str.center(6,"a") //結果:groovy println str.center(7,"a") //結果:groovya println str.center(8,"a") //結果:agroovya println str.center(9,"a") //結果:agroovyaa // 2. padLeft(Number numberOfChars,CharSequence padding) ,在字串的左邊進行填充 // 3. padRight(Number numberOfChars,CharSequence padding),在字串的右邊進行填充 //字串比較: def string = "groovy" def string1 = "Groovy" println string.compareTo(string1) // 32 結果大於0,str大於Str2 println string.compareToIgnoreCase(string1) // 0 結果等於0,str等於忽略大小寫的Str println string1.compareTo(str) // -32 結果小於0,str2小於str println string > string1 // true 可用操作符直接進行比較 println string == string1.toLowerCase() // true //獲取字串中的字元: def string2 = "groovy" println string2.getAt(0) // g println string2.getAt(0..1) // gr println string2[0] // g println string2[0..1] // gr //字串中的減法(取差集): def string3 = "groovy" def string4 = "hello" def string5 = "hello groovy" def string6 = "groovy hello " println string3.minus(string4) // groovy, str中沒有包含str2 println string3.minus(string5) // groovy, str中沒有包含str3 println string5.minus(string4) // groovy, str3中包含了str2 (注意結果包含了空格) println string5.minus(string6) // hello groovy, str3z中沒有包含str4 println string5 - string3 // hello, str3z中包含了str(注意結果包含了空格) // 其它方法 def string7 = "hello groovy" println string7.reverse() // yvoorg olleh,字串反轉 println string7.capitalize()// Hello groovy,首字母大寫 println string7.isNumber() // false,是否全是數字 def string8 = "1234" println string8.toInteger() // 1234 println string8.toBigDecimal() // 1234 println string8.toDouble() // 1234.0 複製程式碼
6. 邏輯控制
- if/else:同Java
- switch/case:Java中switch只能傳入int型別、byte,char和short型別能自動提升為int型別、String型別和後來擴充套件的enum型別。而在Groovy中,switch可以傳入任性型別的資料進行匹配。
String judgeType(Object x) { def result switch (x) { case "string": result = "x is string" break case [4, 5, 6, 7,'inList']: //列表(資料結構中講解) result = "x is in list [4, 5, 6, 7,'inList']" break case 10..15: //範圍range(資料結構中講解) result = "x is in range 10..15" break case Integer: result = "x is Integer" break case BigDecimal: result = "x is BigDecimal" break case List: result = "x is List" break default: result = "no match" break } return result } 複製程式碼
7. 迴圈邏輯
- while迴圈:同Java
- for迴圈
// 1. 範圍中的for迴圈 def sum = 0 for (i in 0..9) { sum += i } println sum // 45 sum = 0 // 2. list中的for迴圈 for (i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) { sum += i } println sum // 45 // 3. map中的for迴圈 for (i in ['java': 1, ' groovy': 2, 'python': 3]) { println "key:${i.key} value:${i.value}" } 複製程式碼
8. 閉包
-
定義:Groovy中的閉包是一個開放的,匿名的程式碼塊,可以接受引數,可以返回值並且可以賦值給閉包變數。閉包可以引用在其周圍範圍內宣告的變數,與閉包的正式定義相反,Groovy語言中的Closure也可以包含在其周圍範圍之外定義的自由變數。
-
語法:{ [closureParameters -> ] statements } 。其中[closureParameters->]是一個以逗號分隔的可選引數列表,而且statements 有0條或更多條Groovy語句,引數看起來類似於方法引數列表,這些引數可以是型別化的或非型別化的。指定引數列表時, - >字元是必需的,用於將引數列表與Groovy語句分開。
-
程式碼示例
{ item++ } //一個引用名為item的變數的閉包 { -> item++ } //通過新增箭頭( - >)可以明確地將閉包引數與程式碼分開 { println it } //使用隱式引數(it)的閉包 { it -> println it } //上面的一個替代版本,它是一個顯式引數 { name -> println name } //在這種情況下,通常最好為引數使用顯式名稱 { String x, int y -> //一個閉包接受兩個型別引數 println "hey ${x} the value is ${y}" } { reader -> //閉包可以包含多個語句 def line = reader.readLine() line.trim() } // 上面程式碼定義一個名為 closure_name 的閉包,用途由 closure body 中的程式碼定義。 // 匿名閉包指不宣告閉包變數名,只有閉包方法體{ //closure body } def closure_name = { // closure body } 複製程式碼
-
閉包類:一個閉包是groovy.lang.Closure類的一個例項,它可以像任何其他變數一樣賦值給變數或欄位,儘管它是一個程式碼塊。Java8中lambda表示式也引入了閉包概念,類com.sun.corba.se.spi.orbutil.closure.Closure。Groovy將閉包定義為Closure類的例項,與Java 8中的lambda表示式截然不同。
-
引數
- 普通引數:閉包的引數和常規方法的引數一樣,遵循相同的原則。
- 隱式引數:當閉包沒有顯式定義引數列表(使用 - >定義)時,閉包總是定義一個名為it的隱式引數。
- 可變引數:閉包可以像任何其他方法一樣宣告可變引數。可變引數方法的特點是:引數的數量是可變的。有2種情況:最後一個引數是可變長度的引數,或者是一個陣列引數。
-
閉包呼叫:def closure_name = { // closure body }
- closure_name.call()
- closure_name()
-
閉包使用:閉包可以用作方法的引數。在Groovy中,很多用於資料型別(例如列表和集合)的內建方法都有閉包作為引數型別。
def clos = { param -> println "${str1} ${param}" } clos("Groovy") clos.call("World"); // 閉包和列表 def lst = [11, 12, 13, 14]; lst.each {println it} // 閉包和對映 def mp = ["TopicName" : "Maps", "TopicDescription" : "Methods in Maps"] mp.each {println it} mp.each {println "${it.key} maps to: ${it.value}"} 複製程式碼
-
閉包進階
- 閉包三個重要變數:this,owner,delegate
// '注:此段程式碼位於HelloWorld.groovy檔案中' // '1. 直接在閉包中使用時: 三者沒有區別' def scriptClosure = { println "scriptClosure this:" + this // 代表閉包定義處的類 println "scriptClosure owner:" + owner // 代表閉包定義處的類或物件(靜態是class檔案,非靜態是物件) println "scriptClosure delegate:" + delegate // 代表任意物件,預設與owner一致 } // 輸出結果: scriptClosure this:main.HelloWorld@6ce139a4 scriptClosure owner:main.HelloWorld@6ce139a4 scriptClosure delegate:main.HelloWorld@6ce139a4 // '2. 閉包內部的閉包,this與 owner和delegate是不同的' /** * 1. 在類或者閉包中定義的閉包,三者沒有區別 * 2. 在閉包中定義的閉包 this 與 owner ,delegate就不一樣了 * 3. this :永遠會指向最外層的類 * 4. owner和delegate預設都會指向定義出最近的closure物件 */ def nestClosure = { def innerClosure = { println "innerClosure this:" + this println "innerClosure owner:" + owner println "innerClosure delegate:" + delegate } innerClosure.call() } nestClosure.call() // 輸出結果: innerClosure this:main.HelloWorld@6ce139a4 innerClosure owner:main.HelloWorld$_run_closure6@33afa13b innerClosure delegate:main.HelloWorld$_run_closure6@33afa13b // '3. 修改delegate指向的物件' def nestClosure = { def innerClosure = { println "innerClosure this:" + this println "innerClosure owner:" + owner println "innerClosure delegate:" + delegate } innerClosure.delegate = new HelloWorld() innerClosure.call() } nestClosure.call() // 輸出結果: innerClosure this:main.HelloWorld@6ce139a4 innerClosure owner:main.HelloWorld$_run_closure6@45b9a632 innerClosure delegate:main.HelloWorld@25d250c6 複製程式碼
- 在大多數情況下 this,owner,delegate的值是一樣的
- 在閉包中定義閉包的時候,this與 owner,delegate就不一樣了
- 在修改了delegate 的值得時候 owner 和 delegate 就不一樣了
- this 與 owner 只要定義了就不可以修改,delegate 可以更改
- this永遠是指定義該閉包類,如果存在內部類,則是最內層的類,但this不是指當前閉包物件
- owner永遠是指定義該閉包的類或者閉包,顧名思義,閉包只能定義在類中或者閉包中
- 閉包的委託策略
// '1. 正常呼叫' class Student { String name def pretty = { println "My name is ${name}" } String toString() { pretty.call() } } class Teather { String name } def student = new Student(name: "groovy") def teather = new Teather(name: "android") student.toString() // 結果:My name is groovy // 原因:每個閉包都會有自己的委託策略,預設的委託策略是 Closure.OWNER_FIRST(因此這也是為什麼大多數情況和owner一致的原因) // 2. '更改委託策略委託' student.pretty.delegate = teather // 更改對應的委託策略委託才真正生效 student.pretty.resolveStrategy = Closure.DELEGATE_FIRST student.toString() // 結果:My name is android 複製程式碼
- Closure.OWNER_FIRST是預設策略。優先在owner尋找,owner沒有再delegate
- Closure.DELEGATE_FIRST:優先在delegate尋找,delegate沒有再owner
- Closure.OWNER_ONLY:只在owner中尋找
- Closure.DELEGATE_ONLY:只在delegate中尋找
- Closure.TO_SELF:高階選項,讓開發者自定義策略。
- 閉包三個重要變數:this,owner,delegate
-
閉包程式碼塊中,只要是this、owner、delegate三者中擁有的屬性和方法,閉包中都是可以直接(可省略引用)呼叫到的。區別在於存在一個執行順序,執行順序是閉包的委託策略決定。
// rootProject : build.gradle buildscript { ScriptHandler scriptHandler -> // 配置工程倉庫地址 scriptHandler.repositories { RepositoryHandler repositoryHandler -> repositoryHandler.jcenter() repositoryHandler.mavenCentral() repositoryHandler.mavenLocal() repositoryHandler.ivy {} repositoryHandler.maven { MavenArtifactRepository mavenArtifactRepository -> mavenArtifactRepository.name 'personal' mavenArtifactRepository.url 'http://localhost:8081/nexus/repositories/' mavenArtifactRepository.credentials { username = 'admin' password = 'admin123' } } } } // ======================== 上述簡化後 ============================= buildscript { /** * 配置工程倉庫地址 * 由於repositories這個閉包中的delegate是repositoryHandler, * 因此可以省略repositoryHandler的引用,直接使用其屬性和方法。 */ repositories { jcenter() mavenCentral() mavenLocal() ivy {} maven { name 'personal' url 'http://localhost:8081/nexus/repositories/' credentials { username = 'admin' password = 'admin123' } } } } 複製程式碼
9. 範圍
- 定義:範圍是指定值序列的速記。範圍由序列中的第一個和最後一個值表示,Range可以是包含或排除。包含範圍包括從第一個到最後一個的所有值,而獨佔範圍包括除最後一個之外的所有值。
- 使用示例:
1..10 - 包含範圍的示例 1 .. <10 - 獨佔範圍的示例 'a'..'x' - 範圍也可以由字元組成 10..1 - 範圍也可以按降序排列 'x'..'a' - 範圍也可以由字元組成並按降序排列。 def range = 1..10 複製程式碼
- 常用方法:
contains() 檢查範圍是否包含特定值 get() 返回此範圍中指定位置處的元素。 getFrom() 獲得此範圍的下限值。 getTo() 獲得此範圍的上限值。 isReverse() 這是一個反向的範圍,反向迭代 size() 返回此範圍的元素數。 subList() 返回此指定的fromIndex(包括)和toIndex(排除)之間的此範圍部分的檢視 複製程式碼
10. 列表
- 定義:列表是用於儲存資料項集合的結構。在Groovy中,List儲存了一系列物件引用。List中的物件引用佔據序列中的位置,並通過整數索引來區分。列表文字表示為一系列用逗號分隔並用方括號括起來的物件。要處理列表中的資料,我們必須能夠訪問各個元素。Groovy列表使用索引操作符[]索引。列表索引從零開始,這指的是第一個元素。
- 使用示例:
[11,12,13,14] - 整數值列表 ['Angular','Groovy','Java'] - 字串列表 [1,2,[3,4],5] - 巢狀列表 ['Groovy',21,2.11] - 異構的物件引用列表 [] - 一個空列表 def arrayList = [1, 2, 3, 4] 複製程式碼
- 常用方法
add() 將新值附加到此列表的末尾。 contains() 如果此列表包含指定的值,則返回true。 get() 返回此列表中指定位置的元素。 isEmpty() 如果此列表不包含元素,則返回true minus() 建立一個由原始元素組成的新列表,而不是集合中指定的元素。 plus() 建立由原始元素和集合中指定的元素組成的新列表。 pop() 從此列表中刪除最後一個專案 remove() 刪除此列表中指定位置的元素。 reverse() 建立與原始列表的元素相反的新列表 size() 獲取此列表中的元素數。 sort() 返回原始列表的排序副本。 複製程式碼
11. 對映
- 定義:對映(也稱為關聯陣列,字典,表和雜湊)是物件引用的無序集合。Map集合中的元素由鍵值訪問。 Map中使用的鍵可以是任何類。當我們插入到Map集合中時,需要兩個值:鍵和值。
- 使用示例:
['TopicName':'Lists','TopicName':'Maps'] - 具有TopicName作為鍵的鍵值對的集合及其相應的值。 [:] - 空對映。 def map = ['key': 'value'] 複製程式碼
- 常用方法
containsKey() 此對映是否包含此鍵? get() 查詢此Map中的鍵並返回相應的值。如果此對映中沒有鍵的條目,則返回null。 keySet() 獲取此對映中的一組鍵。 put() 將指定的值與此對映中的指定鍵相關聯。如果此對映先前包含此鍵的對映,則舊值將替換為指定的值。 size() 返回此地圖中的鍵值對映的數量。 values() 返回此地圖中包含的值的集合檢視。 複製程式碼
12. 物件導向:
- Groovy中類的特點
- Groovy中的類預設都是public型別的,所有的方法變數預設都是public型別的
- Groovy中的類預設整合自GroovyObject ,在這個類中預設實現了getProperty和 setProperty方法。
- Groovy中在建立物件的同時可以對變數進行賦值,可以選擇對部分或者全部進行賦值
- Groovy中無論是直接.變數,還是呼叫get/set方法獲取或者設定變數,最終呼叫的都是get/set。
class HelloGroovy { String name Integer age // def等同於Java中的Object def invokeMethod(String method, Object args){ return "invokeMethod : the method is ${method},the args is ${args}" } static void main(String[] args) { //賦值: 可以不初始化,也可以初始化部分或者全部 def hello = new HelloGroovy(name: "dog",age: 2) //hello.name的方式獲取變數的值,其實最終的實現也是 animal.getName() println "this animal's name is ${hello.name},the animal's age is ${hello.age}" } } 複製程式碼
- Groovy中介面的特點:介面中不許定義非public的方法
- trait:Groovy中獨有的物件導向的語法特性,Trait可以被看作是具有方法實現和狀態的介面。它的使用方法和介面一樣,都是使用implements關鍵字,這個看上去感覺跟繼承有點類似,但又不一樣,trait僅僅是將其方法和狀態嵌入到實現類中,而沒有繼承中的那種上下級的父子關係。
- trait中支援定義抽象方法,其實現類必須實現此抽象方法。
- trait中可以定義私有方法,其實現類無法訪問。
- trait中的this關鍵字指其實現類。
- trait可以實現介面。
- trait中可定義屬性,此屬性會自動被附加到實現此trait的類中。
- trait可定義私有欄位由於儲存相關狀態。
- trait可定義公共欄位,但為了避免鑽石問題,其獲取方式有所不同
- Groovy中方法呼叫的特點:編碼階段,若一個方法不存在時,Groovy並不會報錯。而在執行過程中時,若不存在某方法,則首先會找當前類是否重寫了methodMissing方法,若重寫則呼叫,若methodMissing方法沒有重寫,則會查詢當前類是否重寫了invokeMethod方法,若重寫了則呼叫,否則就會報錯。
class HelloGroovy { /** * 一個方法在找不到時,呼叫這個方法作為代替 * 優先於 invokeMethod() */ def methodMissing(String method, Object args) { return "methodMissing : the method is ${method},the args is ${args}" } // 一個方法在找不到時,呼叫這個方法作為代替 def invokeMethod(String method,Object args){ return "invokeMethod : the method is ${method},the args is ${args}" } static void main(String[] args) { def hello = new HelloGroovy() //呼叫不存在的方法 hello.call() } } 複製程式碼
- Groovy中的超程式設計:
- 使用metaClass() 方法動態的為物件插入屬性
- 使用metaClass() 方法動態的為物件插入方法
- 使用metaClass() 方法動態的為物件插入靜態方法
- 應用功能場景:當我們引用第三方的框架時,很容易引用的到無法修改的jar檔案和final修飾的類,這個時候我們無法修改類的屬性,可我們又特別的希望可以插入一個變數或者插入或修個一個方法,比如破解,這時候如果有了動態注入變數或者是方法,我們就可以輕鬆實現我們的需求了。當然我們這樣動態注入的變數和方法是不能在真的應用中被使用的,有一定的作用域的限制(只能在當前頁面使用)。
class HelloGroovy { String name Integer version static void main(String[] args) { // 超程式設計為類動態注入屬性 HelloGroovy.metaClass.desc = "我是描述資訊" def groovy = new HelloGroovy() groovy.desc = "我是Groovy" println(groovy.desc) // 超程式設計為類動態注入方法 HelloGroovy.metaClass.descUpcase = { it -> it.toUpperCase() } HelloGroovy.metaClass.english = "I am Groovy" def helloGroovy = new HelloGroovy() println helloGroovy.descUpcase(helloGroovy.english) // 超程式設計為類動態注入靜態方法 HelloGroovy.metaClass.static.addVersion = { it -> it + 1 } HelloGroovy.metaClass.desc = "注入靜態方法" def staticInject = new HelloGroovy(name: "groovy", version: 2) println "the language's name is ${staticInject.name}, the language's next version is ${staticInject.addVersion(staticInject.version)}" } } // 輸出結果: 我是Groovy I AM GROOVY the language's name is groovy, the language's next version is 3 複製程式碼
13. 異常處理:類似Java
Groovy的高階語法
1. Json操作
- JsonSlurper:JsonSlurper是一個將JSON文字或閱讀器內容解析為Groovy資料的類結構,例如地圖,列表和原始型別,如整數,雙精度,布林和字串。
- JsonOutput: 此方法負責將Groovy物件序列化為JSON字串。
//Json解析:JSON文字或閱讀器內容解析為Groovy資料結構的類
def jsonSlurper = new JsonSlurper()
// 文字解析
def object = jsonSlurper.parseText('{ "name": "John", "ID" : "1"}')
println(object.name);
println(object.ID);
// 解析整數列表
Object listObj = jsonSlurper.parseText('{ "List": [2, 3, 4, 5] }')
listObj.each { println it }
// 解析基本資料型別列表
def obj = jsonSlurper.parseText ''' {"Integer": 12, "fraction": 12.55, "double": 12e13}'''
println(obj.Integer);
println(obj.fraction);
println(obj.double);
//Json序列化:將Groovy物件序列化為JSON字串
def output = JsonOutput.toJson([name: 'John', ID: 1])
println(output)
class Student{
String name
Integer ID
}
def output1 = JsonOutput.toJson([new Student(name: 'John',ID:1), new Student(name: 'Mark',ID:2)])
println(output1);
複製程式碼
2. XML操作
- XML標記構建器:Groovy支援基於樹的標記生成器BuilderSupport,它可以被子類化以生成各種樹結構物件表示。通常,這些構建器用於表示XML標記,HTML標記。 Groovy的標記生成器捕獲對偽方法的呼叫,並將它們轉換為樹結構的元素或節點。這些偽方法的引數被視為節點的屬性。作為方法呼叫一部分的閉包被視為生成的樹節點的巢狀子內容。
- XML解析器:Groovy XmlParser類使用一個簡單的模型來將XML文件解析為Node例項的樹。每個節點都有XML元素的名稱,元素的屬性和對任何子節點的引用。這個模型足夠用於大多數簡單的XML處理。
//XML解析
def stringXml = '''
<collection shelf = "New Arrivals">
<movie title = "Enemy Behind">
<type>War, Thriller</type>
<format>DVD</format>
<year>2003</year>
<rating>PG</rating>
<stars>10</stars>
<description>Talk about a US-Japan war</description>
</movie>
<movie title = "Transformers">
<type>Anime, Science Fiction</type>
<format>DVD</format>
<year>1989</year>
<rating>R</rating>
<stars>8</stars>
<description>A schientific fiction</description>
</movie>
<movie title = "Ishtar">
<type>Comedy</type>
<format>VHS</format>
<year>1987</year>
<rating>PG</rating>
<stars>2</stars>
<description>Viewable boredom </description>
</movie>
</collection>
'''
def parser = new XmlParser()
// 解析文字
def text = parser.parseText(stringXml)
println text.movie[0].type[0].text()
// 解析檔案
def doc = parser.parse("E:\\CodeProject\\groovy\\HelloWorld\\src\\main\\Movies.xml")
println doc
// 輸出結果:
War, Thriller
collection[attributes={shelf=New Arrivals}; value=[movie[attributes={title=Enemy Behind}; value=[type[attributes={}; value=[War, Thriller]], format[attributes={}; value=[DVD]], year[attributes={}; value=[2003]], rating[attributes={}; value=[PG]], stars[attributes={}; value=[10]], description[attributes={}; value=[Talk about a US-Japan war]]]], movie[attributes={title=Transformers}; value=[type[attributes={}; value=[Anime, Science Fiction]], format[attributes={}; value=[DVD]], year[attributes={}; value=[1989]], rating[attributes={}; value=[R]], stars[attributes={}; value=[8]], description[attributes={}; value=[A schientific fiction]]]], movie[attributes={title=Ishtar}; value=[type[attributes={}; value=[Comedy]], format[attributes={}; value=[VHS]], year[attributes={}; value=[1987]], rating[attributes={}; value=[PG]], stars[attributes={}; value=[2]], description[attributes={}; value=[Viewable boredom]]]]]]
// 解析節點遍歷
doc.movie.each{
bk->
print("Movie Name:")
println "${bk['@title']}"
print("Movie Type:")
println "${bk.type[0].text()}"
print("Movie Format:")
println "${bk.format[0].text()}"
print("Movie year:")
println "${bk.year[0].text()}"
print("Movie rating:")
println "${bk.rating[0].text()}"
print("Movie stars:")
println "${bk.stars[0].text()}"
print("Movie description:")
println "${bk.description[0].text()}"
println("*******************************")
}
//XML標記生成器
def mB = new MarkupBuilder()
// 根節點是誰,呼叫的方法就是誰
mB.collection(shelf : 'New Arrivals') {
movie(title : 'Enemy Behind')
type('War, Thriller')
format('DVD')
year('2003')
rating('PG')
stars(10)
description('Talk about a US-Japan war')
}
// 注1:mB.collection() -這是一個標記生成器,用於建立<collection> </ collection>的頭XML標籤
// 注2:movie(title : 'Enemy Behind') -這些偽方法使用此方法建立帶有值的標記的子標記。通過指定一個名為title的值,這實際上表示需要為該元素建立一個屬性。
// 注3:向偽方法提供閉包以建立XML文件的剩餘元素。
// 根據map生成XML
def mapXml = [1 : ['Enemy Behind', 'War, Thriller','DVD','2003',
'PG', '10','Talk about a US-Japan war'],
2 : ['Transformers','Anime, Science Fiction','DVD','1989',
'R', '8','A scientific fiction'],
3 : ['Trigun','Anime, Action','DVD','1986',
'PG', '10','Vash the Stam pede'],
4 : ['Ishtar','Comedy','VHS','1987', 'PG',
'2','Viewable boredom ']]
// Compose the builder
def MOVIEDB = mB.collection('shelf': 'New Arrivals') {
mapXml.each {
sd ->
mB.movie('title': sd.value[0]) {
type(sd.value[1])
format(sd.value[2])
year(sd.value[3])
rating(sd.value[4])
stars(sd.value[4])
description(sd.value[5])
}
}
}
println MOVIEDB
複製程式碼
3. 檔案IO操作(Groovy在使用IO時提供了許多輔助方法,並提供了更簡單的類操作檔案)
- 讀取檔案
- 寫入檔案
- 遍歷檔案樹
- 讀取和寫入資料物件到檔案
- Groovy的檔案方法會自己幫助我們關閉流,不需要我們關心
// 讀取檔案
def file = new File('src/main/Movies.xml')
file.eachLine {
line -> println "line : $line";
}
// 讀取檔案的內容到字串
println file.text
// 讀取檔案部分內容
def reader = file.withReader {
char[] buff = new char[100]
it.read(buff)
return buff
}
println reader
// 寫入檔案
new File('E:\\CodeProject\\groovy\\HelloWorld','Example.txt').withWriter('utf-8') {
writer -> writer.writeLine 'Hello World'
}
// 獲取檔案的大小
println file.length()
// 測試檔案是否是目錄
println "File? ${file.isFile()}"
println "Directory? ${file.isDirectory()}"
// 建立目錄
def fileMkDir = new File('E:\\CodeProject\\groovy\\HelloWorld\\IO')
fileMkDir.mkdir()
// 刪除檔案
fileMkDir.delete()
// 複製檔案
def src = new File("E:\\CodeProject\\groovy\\HelloWorld\\Example.txt")
def dst = new File("E:\\CodeProject\\groovy\\HelloWorld\\Example1.txt")
dst << src.text
// 獲取目錄內容
def rootFiles = file.listRoots()
rootFiles.each {
println it.absolutePath
}
// 物件儲存,寫入檔案
def saveObject(Object o, String path) {
//判斷目標檔案不存在,建立檔案
File destFile = new File(path)
try {
if (!destFile.exists()) {
destFile.createNewFile()
}
} catch (Exception e) {
e.printStackTrace()
}
if (o == null) {
return
}
try {
destFile.withObjectOutputStream { outputStream ->
outputStream.writeObject(o)
}
} catch (Exception e) {
e.printStackTrace()
}
}
// 拷貝檔案
def copy(String sourcePath, String destationPath) {
//判斷目標檔案不存在,建立檔案
File destFile = new File(destationPath)
try {
if (!destFile.exists()) {
destFile.createNewFile()
}
} catch (Exception e) {
e.printStackTrace()
}
File sourceFile = new File(sourcePath)
try {
if (!sourceFile.exists()) {
return
}
} catch (Exception e) {
e.printStackTrace()
return
}
def lines = sourceFile.readLines()
destFile.withWriter {writer->
lines.each {line->
writer.append(line).append('\r\n')
}
}
}
複製程式碼
參考連結
注:若有什麼地方闡述有誤,敬請指正。期待您的點贊哦!!!