Groovy瞭解

Apache Groovy是一種強大的、可選類型的動態語言,具備靜態類型和靜態編譯功能,因爲具備簡潔、熟悉和易於學習的語法,Java平臺旨在提升開發人員的工做效率。它能夠與任何Java程序順暢地集成,並當即嚮應用程序交付強大的特性,包括腳本功能、特定領域的語言創做、運行時和編譯時元編程以及函數式編程(官方文檔對groovy描述)。html

Groovy 開發環境安裝

brew install groovy
複製代碼
  • 安裝完成在.bash_profile 文件中配置環境變量(MacOs)
You should set GROOVY_HOME:
  export GROOVY_HOME=/usr/local/opt/groovy/libexec
複製代碼
  • 最後看看版本號是否安裝成功
groovy -v

## 打印輸出
Groovy Version: 3.0.4 JVM: 14.0.1 Vendor: Oracle Corporation OS: Mac OS X
複製代碼

Groovy 基本認識

  • groovy 註釋和 Java 同樣 支持 // 和 /**/
  • groovy 語法和 kotlin 同樣不須要寫 ;
  • groovy 支持動態類型,定義變量可使用 def 關鍵字
def a = 1
def s = "test"
def int b = 1 //定義變量也能夠知道類型
複製代碼
  • 定義函數也無需指定參數類型和和返回值類型
def test(arg1,arg2){ //定義兩個參數 arg1 arg2
     //邏輯代碼
     ....
    
    // 函數最後一行爲返回值 函數返回值爲 int 類型
    10
}

String test2(arg1,arg2){ //指定返回值類型 String 則沒必要寫關鍵字 def
     //邏輯代碼
     ....
    
    // 函數最後一行爲返回值 函數返回值爲 String 類型
    //函數指定返回值 則返回值必須一致
    // return 可寫可不寫
    return "aaa"
}

複製代碼
  • 調用函數能夠不帶括號,可是建議仍是要帶上括號,不然如何函數須要輸入參數就會吧函數調用和屬性混淆
//打印輸出 hello
println("hello")

//能夠寫成
println "hello"
複製代碼

Groovy 語法

Gradle Hello

  • 國際慣例,首先來看看一個語言的 hello world,新建一個 test.groovy,使用 groovy test.groovy 運行
println("hello groovy")
複製代碼
  • 運行結果

groovy test.groovy

基本數據類型

  • groovy 語言全部東西都是對象,和Java同樣,它也有 int,long ,boolean 這些基本數據類型,不過咱們不要顯示聲明,groovy會自行判變量類型,在 Groovy 代碼中其實對應的是它們的包裝數據類型。好比 int 對應爲 Integer,long 對應爲 Long。
def a = 1
def b = "hello groovy"
def c = false
def d = 10000000000000
println a.getClass().getCanonicalName()
println b.getClass().getCanonicalName()
println c.getClass().getCanonicalName()
println d.getClass().getCanonicalName()
複製代碼
  • 執行結果

groovy基本數據類型執行結果

Groovy 中的容器類

  • groovy 容器類有三種,分別爲爲 List、Map和Range,對應到 Java 則爲 ArrayList、LinkedHashMap 和對 List 的擴展

groovy List

  • List 對應由 [] 括號定義,其數據類型可使任何的對象
//隨意添加各類類型對象 變量打印

def aList = [5,'string',true]
//元素變量
aList.each {
   //it是是與當前元素對應的隱式參數
    println "Item: $it"
}

//添加元素

//查找元素 find 方法
//
println(aList.find{ it > 1 })
println(aList.findAll{ it > 1 })

//刪除元素

//執行結果
Item: 5
Item: string
Item: true
複製代碼

groovyList操做執行結果

groovy Map

  • Map 變量由 [:] 符號定義,冒號左邊是 key,右邊是 Value。key 必須是字符串,value 能夠是任何對 象。另外,key 能夠用''或""包起來,也能夠不用引號包起來
//其中的 key1 和 key2 默認被處理成字符串"key1"和"key2"
def aNewMap = [key1:"hello",key2:false]
//map 取值
println aNewMap.key1
println aNewMap['key2']
//爲 map 添加新元素
aNewMap.anotherkey = "i am map"

aNewMap.each{
    println "Item: $it"
}

//執行結果
hello
false
Item: key1=hello
Item: key2=false
Item: anotherkey=i am map
複製代碼

groovy Range

  • Range 由字面意思是範圍,它其實爲List的擴展,表明一個List 的範圍,由 begin 值+兩個點+end 值表示
//標識 list 至關於數學閉包 [1,5]
def mRange = 1..5

mRange.each {
    println "Item: $it"
}

//標識 list 至關於數學閉包 [1,5)
def mRange1 = 1..<5

mRange1.each {
    println "other Item: $it"
}

//獲取開頭結尾元素
println mRange.from
println mRange.to
複製代碼

groovyRange執行結果

groovy-lang API 文檔

Groovy 閉包(Closure)

  • Groovy語言的閉包,英文叫 Closure,是一種數據類型,它表明了一段可執行的代碼
  • 閉包格式
//格式一 有參數
def xxx = {
params -> 
//返回值
code邏輯
} 

//格式二 無參數 不須要 ->
def xxx = {
  code 邏輯
} 
複製代碼
  • 示例
//閉包是一段代碼,因此須要用花括號括起來
def testClosure = {
        //箭頭前面是參數定義,箭頭後面是代碼
String param1, int param2 ->
        //邏輯代碼,閉包最後一句是返回值
    println "hello groovy,$param1,$param2"
    //也可使用 return,和 groovy 中普通函數同樣
}
//閉包調用
testClosure.call("參數1",20)
testClosure("參數2",40)
//輸出結果
hello groovy,參數1,20
hello groovy,參數2,40
複製代碼
  • 若是閉包沒定義參數的話,則隱含有一個參數 it,和 this 的做用類

似,it 表明閉包的參數,以下示例。java

def greeting = {
//隱含參數
    "Hello, $it!"
}
println greeting('groovy') == 'Hello, groovy!'
//等同於:
def greeting1 = {
        //也可寫出隱含參數
    it -> "Hello, $it!"
}
println greeting1('groovy') == 'Hello, groovy!'

//輸出結果 不用說確定都爲 true
複製代碼
  • 閉包省略括號,經常使用 doLast 函數
task hello{
    doLast ({
        //邏輯代碼
        println'aaaaaa'
    })
}

//省略括號變成經常使用寫法
task hello{
    doLast {
        //邏輯代碼
        println'aaaaaa'
    }
}
複製代碼

groovy 文件 I/O 操做

  • 對於文件的讀取寫入,groovy也是有 api 的,它實際上是對於本來的 Java 的 I/O 操做進行了一些封裝,並加入閉包(Closure)來簡化代碼。新建測試文件 TestFile.txt

讀文件

def testFile = new File("TestFile")

//讀文件每一行 eachLine

testFile.eachLine{
    String oneLine ->
    //打印每一行內容
        println oneLine
}

//獲取文件 byte 數組

def bytes = testFile.getBytes()


//獲取文件輸入流

def is = testFile.newInputStream()

//和Java 同樣不用須要關閉
is.close

//閉包 Groovy 會自動替你 close 
targetFile.withInputStream{ ips ->
    //邏輯代碼
}
複製代碼

寫文件

  • 將上述 TestFile 複製到 CopyFile
def copyFile = new File("CopyFile")

copyFile.withOutputStream{
    os->
        testFile.withInputStream{
            ips ->
            // << 是 groovy OutputStream 的操做符,它能夠完成 InputStream 到 OutputStream 輸出
                os << ips
        }
}

copyFile.eachLine{
    String oneLine ->
        println "copyFile oneLine:$oneLine"
}
複製代碼

groovy複製文件內容執行結果

XML操做

  • 除了讀取普通文件,groovy 也能夠解析 XML 文件,它提供了一個 GPath 類來幫助解析 XML,平時使用 Gradle 可能須要讀取清單文件(AndroidManifest)中一些數據
//建立 XmlSlurper 類

def xmlspr = new XmlSlurper()

//獲取清單文件 file

def file = new File("AndroidManifest.xml")

//獲取解析對象
//獲取清單文件根元素,也就是 manifest 標籤
def manifest = xmlspr.parse(file)

// 聲明命名空間
//manifest.declareNamespace('android':'http://schemas.android.com/apk/res/android')
//獲取包名
println manifest.'@package'

//獲取 activity intent-filter

def activity = manifest.application.activity
//獲取 intent-filter 設置的過濾條件 也能夠此判斷是否爲應用程序入口 activity
activity.find{
   it.'intent-filter'.find { filter ->
       filter.action.find{
           println it.'@android:name'.text()
       }
       filter.category.find{
           println it.'@android:name'.text()
       }
   }
}
複製代碼

解析清單文件執行結果

更多介紹 api 官方文檔

groovy 腳本究竟是什麼

  • 首先能夠像Java 那樣寫 groovy class,新建一個groovyclass目錄,而後編寫GroovyClass類
package groovyclass

class GroovyClass{

    String p1;
    int p2;

    GroovyClass(p1,p2){
        this.p1 = p1
        this.p2 = p2
    }

    //和 Java 相似 若是不聲明 public/private
    //等訪問權限的話,Groovy 中類及其變量默認都是 public

    def printParams(){
        println "參數:$p1,$p2"
    }
}
複製代碼
  • 上面代碼是否是很熟悉,而在其餘文件須要使用則 improt 引入,以下新建 testClass.groovy 文件
import groovyclass.GroovyClass

def g = new GroovyClass("hello",100)
g.printParams()
複製代碼

groovyclass執行結果

groovy 腳本原理

  • 前面這麼多例子,執行都是利用命令 groovy XXXX 命令執行 groovy 腳本文件,而 groovy 最終會變成字節碼.class 基於JVM 虛擬機的運行的,則能夠猜測,在變成字節碼以前是否會轉變成 Java 文件呢?以下再次看到文章開頭的 test.groovy 文件
println("hello groovy")
複製代碼
  • 對該文件執行以下命令
groovyc -d classes test.groovy
複製代碼
  • groovyc 命令是 groovy 的編譯命令,同時將編譯以後的字節碼文件複製到當前目錄下的classes文件夾,獲得的 class 文件以下

groovyclass文件

  • 1.由上圖,首先 test.groovy 被轉換成了 test 類,並繼續 Script 類
  • 2.其次,使用 CallSite 類型數組分別保存類對象和 groovy腳本中編寫的代碼
  • 3.而後爲這個類建立了靜態 main 方法,並在 main 方法中動態代理調用 test 類的 run 方法
  • 4.最後 run 方法執行 groovy 腳本編寫的代碼
  • 到此,是否會有豁然開朗的感受,當咱們使用命令groovy XXXX執行 groovy 腳本,實際上是執行編譯生成類對象的靜態main方法,並在main方法中動態代理類對象執行了它的run方法來執行腳本中的邏輯。

demo

更多文章

參考