Gradle 之語言基礎 Groovy

最近在學習 Android 中 Gradle 相關的知識,若是想學好 Gradle,必要的 Groovy 基礎是不可少的。Groovy 語言的知識也是很是多的,若是隻是想在 Android Gradle 這個範圍內使用 Groovy,會 Groovy 的基礎便可,Groovy 語言文檔html

一. Android Gradle 概述

Groovy 是從 Java 衍生出來的,Groovy 的源代碼文件 .groovy 也是編譯成爲 .class 文件,而後運行在 JVM 虛擬機上的。其目標是,不論是做爲腳本語言,仍是編程語言,均可以簡單、直接的使用。在 Android 的 Gradle 中,Groovy 更多的是用於編寫腳本。若是會 Java,學習 Groovy 會比較簡單,甚至能夠混寫 Java 和 Groovy 語法。java

Groovy 相比 Java 語言來說,更加的方便靈活,更多的語法糖使編寫 Groovy 代碼更加的簡潔,並且在 Groovy 中具備函數式編程的思想。好比:Groovy 中很是重要的閉包 Closure 概念(相似於 C 語言中的函數指針),能夠當作一個函數也執行,也能夠當作某個函數的參數傳入到函數中去,也能夠當作一個函數的返回值返回。android

想學好 Gradle,除了必要的 Groovy 知識基礎之外,還須要瞭解其餘兩個基礎知識:Android DSL 和 Gradle DSL。 DSL 是 Domain Specific Language(領域特定語言)的縮寫,其定義是:針對某一領域,具備受限表達性的一種計算機程序設計語言。學習 Android Gradle,Android DSL 和 Gradle DSL 也是須要學習的,好在有官方的文檔 Android DSL 文檔Gradle DSL 文檔,學習起來就比較方便。在這篇文章中,不會過多地介紹 Android DSL 和 Gradle DSL,在下篇文章中會介紹。git

好了,廢話很少說,接下來就來學習 Groovy 的語法基礎吧。爲了學習的時候,能夠執行 gradle 腳本,請先在電腦上配置好 gradle 的環境變量,這樣就能夠方便地執行 gradle 腳本了。github

二. Groovy 語言基礎

因爲篇幅所限,本篇文章也只能做爲一個引子,介紹基礎的 Groovy 語言概念,詳細的還須要從 Groovy 語言文檔 學習。並且我我的認爲,若是遇到什麼不懂的、不會的,從官方文檔上學習是最好的學習途徑;或者至少先從官方文檔上學習,再去學習其餘的資料,將本身學習的和資料的進行對比思考,這樣會更有助於我的的成長編程

爲了不無心義的內容,只介紹和 Java 有區別的地方,相同的地方不做說明。數組

2.1 變量

  1. Groovy 中聲明的變量,默認的修飾符是 public 的
  2. Groovy 中聲明變量時,若是一行只聲明一個變量則能夠省略末尾的 ;,可是若是一行聲明瞭多個變量,變量與變量之間則不能夠省略 ;
  3. 在 Groovy 中聲明變量,也可使用關鍵字 defdef 只是聲明瞭一個變量,變量的實際類型根據該變量的對象決定。def 和 JavaScript 中的 val 有點像,從 def 能夠看出 Groovy 也是一門動態語言
  4. Groovy 中字符串 String,可使用單引號 'String',也可使用雙引號 "String"
  5. 在 Groovy 中的 String,能夠經過 ${} 作佔位符表達式向字符串中插入值,在 {} 中寫表達式或變量均可以,使用 ${} 的字符串必須使用雙引號 ""
int version = 1
Boolean isDebug = true
def language = 'groovy'
def message = "Hello from ${language + 1}, the result is ${isDebug}."

task hello {
	doLast{
		println message	
	}
}
複製代碼

上面代碼的執行輸出是:bash

> Task :hello
Hello from groovy1, the result is true.
複製代碼

2.2 List

  1. 由於在 Groovy 中沒有定義任何集合類,因此 Groovy 中的 List 使用的是 JDK 中的 java.util.List
  2. 在 Groovy 中的一個 List 中能夠添加多種類型的對象元素
  3. 建立 List 對象使用 [],而不是 Java 中的 {},防止和 Groovy 中的 閉包 Closure {} 混淆
  4. 能夠經過 [index] 的方式修改和訪問 List 中的元素
  5. 能夠經過 << 向 List 中添加元素,<< 實際是 leftShift() 方法
  6. 能夠經過負數,從後向前訪問 List 中的元素,好比 [-1] 表示最後一個元素
  7. 能夠經過 [index1, index2] 同時訪問 List 中的多個元素,返回結果還是一個List
  8. 能夠經過 [index1..index2] 一次性訪問 List 中某個範圍內的數組,返回結果也是一個 List
ArrayList arrayList = ['arrayOne', 'arrayTwo', 'arrayThree']
LinkedList linkedList = ['linkedOne', 'linkedTwo', 'linkedThree']
List list = [1, 2, true]
def listDef = ['one', 2, true, 4, '5']

task helloList {
    doLast {
        println listDef
        println arrayList
        println linkedList
        println list
        println list[0]
        println list[-1]
        list << 4
        println list[-1]
        println list[1, 3]
        println list[1..3]
    }
}
複製代碼

輸出以下所示:閉包

> Task :app:helloList
[one, 2, true, 4, 5]
[arrayOne, arrayTwo, arrayThree]
[linkedOne, linkedTwo, linkedThree]
[1, 2, true]
1
true
4
[2, 4]
[2, true, 4]

複製代碼

2.3 Arrays

Groovy 中的數組和 Java 中的數組區別並不大,也不過多的作介紹app

  1. Groovy 中的數組使用 [] 初始化,並不使用 {},防止和 Groovy 中的 閉包 Closure {} 混淆
  2. 數組不支持 << 向 Arrays 中添加元素
String[] arrayStrings = ["one", "two", 'three'];
def arrayInts = [1, 2, 3] as int[]

task hello {

	doLast {
		println arrayStrings[0]
		println arrayStrings[1]
		println arrayStrings[-1]
		// arrayStrings << 'four' // Arrays 不支持 << 
		println arrayStrings
		println arrayInts
	}
}
複製代碼

輸出以下所示:

> Task :hello
one
two
three
[one, two, three]
[1, 2, 3]
複製代碼

2.4 Map

  1. Groovy 中的 Map 是以 : 做爲 key 和 value 的鏈接,而且以 , 作爲每一項的分隔符的
  2. Map 中的 key 既能夠是字符串也能夠是阿拉伯數字
  3. 能夠經過 [key].key 的形式訪問或向 map 中賦值,訪問的時候若是不存在該 key,則會返回 null
  4. 若是以變量做爲 key 訪問 map 時,記得須要加上 ()
def maps = [red: '#FF0000', green: '#00FF00', blue: '#0000FF']
def mapNums = [1: 'one', 2: 'two', 3: 'three', 100: 'four']

def key = 'name'
def mapKey = [key: 'value']
def mapKey1 = [(key): 'value1']

task helloMaps {

    doLast {

        println maps['red']
        println maps.green
        maps['pink'] = '#FF00FF'
        maps.yello = '#FFFF00'
        println maps['pink']
        println maps.yello
        println maps.white

        println mapNums[1]
        println mapNums[100]
        println mapNums[5]

        println mapKey['key']
        println mapKey['name']

        println mapKey1['name']
    }
}
複製代碼

上述代碼的輸出是

> Task :app:helloMaps
#FF0000
#00FF00
#FF00FF
#FFFF00
null
one
four
null
value
null
value1
複製代碼

2.5 Class 和對象

Groovy 中的 Class 和 Java 中的 Class 區別並不大,主要有如下幾個區別

  1. 若是類、方法沒有修飾符的話,默認是 public 修飾符的
  2. 若是類中的變量 fields 沒有被修飾符修飾的話,會自動成爲一個 propertiesproperties 是公有的,而且會自動生成該 properties 的 setter 和 getter 方法
  3. 在 Java 中,文件名和主類的名稱必須一致,可是 Groovy 中並無這個限制,且在一個 Groovy 文件中能夠出現多個 public 的類
  4. 在一個 Groovy 文件中能夠在類以外定義方法或語句,這種文件就是腳本了
class Student {
    def name
    def age
    private String work
    public String lover

    def Student(String name) {
        this.name = name
    }
}

task helloClass {

    doLast {
        def student = new Student('lijiankun24')
        println student.name
        println student.getAge()
        println student.lover
        // println student.getLover() // Student 中並無 getLover() 這個方法
        // println student.getWork() // Student 中並無 getWork() 這個方法
    }
}
複製代碼

輸出結果以下:

> Task :app:helloClass
lijiankun24
null
null
複製代碼

2.6 函數

Groovy 中的函數和 Java 中的函數並無太大的區別

  1. 函數必定會有返回值,若是沒有顯示的使用 return 返回值的話,函數的最後一行語句的執行結果做爲值返回,可能返回值是個 null
  2. 若是函數有參數,調用函數的時候,能夠省略函數的括號,函數名和參數之間須要用空格間隔;若是函數沒有參數,調用函數的時候就不能省略括號
  3. 函數內不能夠訪問函數外的變量
def message = 'message'

def printMessage () {
    println message
}

void printName(String name) {
    println name
}

void printPerson(String name, age) {
    println "The name is ${name} and the age is ${age}"
}

task helloFunction {
    doLast {
        println printName('xiaoming')

        printPerson  'xiaoming', 20

        // println printMessage() 會執行異常
    }
}
複製代碼

輸出結果以下所示:

> Task :app:helloFunction
xiaoming
null
The name is xiaoming and the age is 20
複製代碼

2.7 閉包 Closure

閉包 closure 是 Java 中沒有的,也是須要重點學習的,學好 closure 對理解 Android 中的 Gradle 會有莫大的幫助

  1. 閉包 closure 的定義以下,其中 [closureParameters ->] 做爲參數部分,是能夠省略的
{ [closureParameters -> ] statements }
複製代碼
  1. closure 實際上是 Groovy 中 groovy.lang.Closure 的一個類
  2. 閉包 closure 能夠訪問閉包以外的變量
  3. 閉包 closure 能夠有三種調用方式,以下代碼所示
  4. 閉包 closure 的參數能夠省略,默認是有個 it 參數的
  5. 閉包 closure 也能夠做爲另外一個閉包 closure 的參數
// 閉包能夠訪問閉包以外的變量
def message = 'closure is good'
def printMessage = {
    println "The message is '${message}'"
}

// 閉包其實是一個 `groovy.lang.Closure` 類
Closure<Boolean> booleanClosure = {
    return it == 'xiaoming'
}

// 閉包能夠省略參數,默認有一個 `it` 的參數
def testClosure = {
    println "I am a closure, the params is ${it}."
}

// 閉包能夠有多個參數,參數能夠指定類型,也能夠不指定類型
def testClosureParams = { name, int age ->
    println "I am a closure, the params is ${name}."
}

// 閉包能夠做爲另外一個閉包的參數
def paramsClosure = { name, closure ->
    if (closure(name)) {
        println 'The input name is xiaoming'
    } else {
        println 'The input name is not xiaoming'
    }
}

task helloClosure {
    doLast {
        printMessage()
        println booleanClosure('xiaoming')
        println booleanClosure('test')

        // 閉包的三種調用方式
        testClosure 'xiaoming'
        testClosure.call('xiaoming')
        testClosure('xiaoming')

        testClosureParams('xiaoming', 20)
        
        // 閉包 booleanClosure 做爲閉包 paramsClosure 的參數
        paramsClosure('xiaoming', booleanClosure)
        paramsClosure('test', booleanClosure)

        // 能夠在調用閉包的時候纔去定義參數閉包的定義,使用很是方便簡潔
        paramsClosure('xiaoming', { name ->
            name.toUpperCase() == 'XIAOMING'
        })
    }
}
複製代碼

輸出以下所示

> Task :app:helloClosure
The message is 'closure is good'
true
false
I am a closure, the params is xiaoming.
I am a closure, the params is xiaoming.
I am a closure, the params is xiaoming.
I am a closure, the params is xiaoming.
The input name is xiaoming
The input name is not xiaoming
The input name is xiaoming
複製代碼

Groovy 的基礎知識就是這麼多,若是想學習更多的內容,建議學習 Groovy 文檔