Gradle自動化專案構建之快速掌握Groovy

若丶相見發表於2019-12-10

Gradle自動化專案構建之快速掌握Groovy

Groovy介紹

  1. 是一種基於JVM的敏捷開發語言
  2. 結合了Python、Ruby、Smalltalk的許多強大特性
  3. Groovy可以與Java完美結合,而且可以使用Java所有的庫

Groovy特性

  1. 語法上支援動態型別,閉包等新一代語言特性
  2. 無縫整合所有已存在的Java類庫
  3. 即支援物件導向程式設計也支援程式導向程式設計

Groovy優勢

  1. 一種更加敏捷的程式語言
  2. 入門非常容易,但功能非常強大
  3. 即可以作為程式語言也可以作為指令碼語言
  4. 熟悉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中的變數

  1. 變數的型別:基本型別(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中的基本型別最終會被編譯器包裝成物件型別

  2. 變數的定義:強型別定義方式和弱型別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. 字串詳解

  1. 兩種字串:String(同Java中的String一樣)、GString
  2. 字串常用的三種定義方式
    //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}"
    複製程式碼
  3. String方法來源
    • java.lang.String原有的方法
    • DefaultGroovyMethods:是Groovy對所有物件的一個擴充套件
    • StringGroovyMethods:繼承自DefaultGroovyMethods,重寫了DefaultGroovyMethods中的許多方法,使這些方法更加適用於String使用。
  4. Groovy中的兩種字串,對於開發者都是字串,和之前正常定義即可。兩者之間的轉換都是編譯器完成的,開發者不關注這些。即便定義的是Java的String,可以使用GString的方法,最終的轉換都是編譯器完成。因此,String 和GString之間可以相互呼叫和傳遞,不需要考慮它們之間的轉換問題。
  5. 字串方法
    //字串填充:
    // 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. 邏輯控制

  1. if/else:同Java
  2. 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. 迴圈邏輯

  1. while迴圈:同Java
  2. 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. 閉包

  1. 定義:Groovy中的閉包是一個開放的,匿名的程式碼塊,可以接受引數,可以返回值並且可以賦值給閉包變數。閉包可以引用在其周圍範圍內宣告的變數,與閉包的正式定義相反,Groovy語言中的Closure也可以包含在其周圍範圍之外定義的自由變數。

  2. 語法:{ [closureParameters -> ] statements } 。其中[closureParameters->]是一個以逗號分隔的可選引數列表,而且statements 有0條或更多條Groovy語句,引數看起來類似於方法引數列表,這些引數可以是型別化的或非型別化的。指定引數列表時, - >字元是必需的,用於將引數列表與Groovy語句分開。

  3. 程式碼示例

    { 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
    }
    複製程式碼
  4. 閉包類:一個閉包是groovy.lang.Closure類的一個例項,它可以像任何其他變數一樣賦值給變數或欄位,儘管它是一個程式碼塊。Java8中lambda表示式也引入了閉包概念,類com.sun.corba.se.spi.orbutil.closure.Closure。Groovy將閉包定義為Closure類的例項,與Java 8中的lambda表示式截然不同。

  5. 引數

    1. 普通引數:閉包的引數和常規方法的引數一樣,遵循相同的原則。
    2. 隱式引數:當閉包沒有顯式定義引數列表(使用 - >定義)時,閉包總是定義一個名為it的隱式引數。
    3. 可變引數:閉包可以像任何其他方法一樣宣告可變引數。可變引數方法的特點是:引數的數量是可變的。有2種情況:最後一個引數是可變長度的引數,或者是一個陣列引數。
  6. 閉包呼叫:def closure_name = { // closure body }

    1. closure_name.call()
    2. closure_name()
  7. 閉包使用:閉包可以用作方法的引數。在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}"}
    複製程式碼
  8. 閉包進階

    1. 閉包三個重要變數: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永遠是指定義該閉包的類或者閉包,顧名思義,閉包只能定義在類中或者閉包中
    2. 閉包的委託策略
      // '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:高階選項,讓開發者自定義策略。
  9. 閉包程式碼塊中,只要是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. 範圍

  1. 定義:範圍是指定值序列的速記。範圍由序列中的第一個和最後一個值表示,Range可以是包含或排除。包含範圍包括從第一個到最後一個的所有值,而獨佔範圍包括除最後一個之外的所有值。
  2. 使用示例:
    1..10 - 包含範圍的示例
    1 .. <10 - 獨佔範圍的示例
    'a'..'x' - 範圍也可以由字元組成
    10..1 - 範圍也可以按降序排列
    'x'..'a' - 範圍也可以由字元組成並按降序排列。
    def range = 1..10
    複製程式碼
  3. 常用方法:
    contains()      檢查範圍是否包含特定值
    get()           返回此範圍中指定位置處的元素。
    getFrom()       獲得此範圍的下限值。
    getTo()         獲得此範圍的上限值。
    isReverse()     這是一個反向的範圍,反向迭代
    size()          返回此範圍的元素數。
    subList()       返回此指定的fromIndex(包括)和toIndex(排除)之間的此範圍部分的檢視
    複製程式碼

10. 列表

  1. 定義:列表是用於儲存資料項集合的結構。在Groovy中,List儲存了一系列物件引用。List中的物件引用佔據序列中的位置,並通過整數索引來區分。列表文字表示為一系列用逗號分隔並用方括號括起來的物件。要處理列表中的資料,我們必須能夠訪問各個元素。Groovy列表使用索引操作符[]索引。列表索引從零開始,這指的是第一個元素。
  2. 使用示例:
    [11,12,13,14] - 整數值列表
    ['Angular''Groovy''Java'] - 字串列表
    [1,2,[3,4],5] - 巢狀列表
    ['Groovy',21,2.11] - 異構的物件引用列表
    [] - 一個空列表
    def arrayList = [1, 2, 3, 4]
    複製程式碼
  3. 常用方法
    add()           將新值附加到此列表的末尾。
    contains()      如果此列表包含指定的值,則返回true。
    get()           返回此列表中指定位置的元素。
    isEmpty()       如果此列表不包含元素,則返回true
    minus()         建立一個由原始元素組成的新列表,而不是集合中指定的元素。
    plus()          建立由原始元素和集合中指定的元素組成的新列表。
    pop()           從此列表中刪除最後一個專案
    remove()        刪除此列表中指定位置的元素。
    reverse()       建立與原始列表的元素相反的新列表
    size()          獲取此列表中的元素數。
    sort()          返回原始列表的排序副本。
    複製程式碼

11. 對映

  1. 定義:對映(也稱為關聯陣列,字典,表和雜湊)是物件引用的無序集合。Map集合中的元素由鍵值訪問。 Map中使用的鍵可以是任何類。當我們插入到Map集合中時,需要兩個值:鍵和值。
  2. 使用示例:
    ['TopicName''Lists''TopicName''Maps'] - 具有TopicName作為鍵的鍵值對的集合及其相應的值。
    [:] - 空對映。
    def map = ['key': 'value']
    複製程式碼
  3. 常用方法
    containsKey()   此對映是否包含此鍵?
    get()           查詢此Map中的鍵並返回相應的值。如果此對映中沒有鍵的條目,則返回null。
    keySet()        獲取此對映中的一組鍵。
    put()           將指定的值與此對映中的指定鍵相關聯。如果此對映先前包含此鍵的對映,則舊值將替換為指定的值。
    size()          返回此地圖中的鍵值對映的數量。
    values()        返回此地圖中包含的值的集合檢視。
    複製程式碼

12. 物件導向:

  1. Groovy中類的特點
    1. Groovy中的類預設都是public型別的,所有的方法變數預設都是public型別的
    2. Groovy中的類預設整合自GroovyObject ,在這個類中預設實現了getProperty和 setProperty方法。
    3. Groovy中在建立物件的同時可以對變數進行賦值,可以選擇對部分或者全部進行賦值
    4. 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}"
            }
        }
    複製程式碼
  2. Groovy中介面的特點:介面中不許定義非public的方法
  3. trait:Groovy中獨有的物件導向的語法特性,Trait可以被看作是具有方法實現和狀態的介面。它的使用方法和介面一樣,都是使用implements關鍵字,這個看上去感覺跟繼承有點類似,但又不一樣,trait僅僅是將其方法和狀態嵌入到實現類中,而沒有繼承中的那種上下級的父子關係。
    1. trait中支援定義抽象方法,其實現類必須實現此抽象方法。
    2. trait中可以定義私有方法,其實現類無法訪問。
    3. trait中的this關鍵字指其實現類。
    4. trait可以實現介面。
    5. trait中可定義屬性,此屬性會自動被附加到實現此trait的類中。
    6. trait可定義私有欄位由於儲存相關狀態。
    7. trait可定義公共欄位,但為了避免鑽石問題,其獲取方式有所不同
  4. 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()
        }
    }
    複製程式碼
  5. Groovy中的超程式設計:
    1. 使用metaClass() 方法動態的為物件插入屬性
    2. 使用metaClass() 方法動態的為物件插入方法
    3. 使用metaClass() 方法動態的為物件插入靜態方法
    4. 應用功能場景:當我們引用第三方的框架時,很容易引用的到無法修改的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操作

  1. JsonSlurper:JsonSlurper是一個將JSON文字或閱讀器內容解析為Groovy資料的類結構,例如地圖,列表和原始型別,如整數,雙精度,布林和字串。
  2. 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操作

  1. XML標記構建器:Groovy支援基於樹的標記生成器BuilderSupport,它可以被子類化以生成各種樹結構物件表示。通常,這些構建器用於表示XML標記,HTML標記。 Groovy的標記生成器捕獲對偽方法的呼叫,並將它們轉換為樹結構的元素或節點。這些偽方法的引數被視為節點的屬性。作為方法呼叫一部分的閉包被視為生成的樹節點的巢狀子內容。
  2. 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時提供了許多輔助方法,並提供了更簡單的類操作檔案)

  1. 讀取檔案
  2. 寫入檔案
  3. 遍歷檔案樹
  4. 讀取和寫入資料物件到檔案
  5. 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')
        }
    }
}

複製程式碼

參考連結

Groovy基礎

www.jianshu.com/p/8127742e0…

blog.csdn.net/liao_hb/art…

注:若有什麼地方闡述有誤,敬請指正。期待您的點贊哦!!!

相關文章