Gradle 之語言基礎 Groovy

最近在學習 Android 中 Gradle 相關的知識,如果想學好 Gradle,必要的 Groovy 基礎是不可少的。Groovy 語言的知識也是非常多的,如果只是想在 Android Gradle 這個范圍內使用 Groovy,會 Groovy 的基礎即可,Groovy 語言文檔。本篇文章主要介紹了 Groovy 中的變量、String、List、Map、類和對象、閉包等內容,示例代碼都在 GradleForAndroid

一. Android Gradle 概述

Groovy 是從 Java 衍生出來的,Groovy 的源代碼文件 .groovy 也是編譯成為 .class 文件,然后運行在 JVM 虛擬機上的。其目標是,不管是作為腳本語言,還是編程語言,都可以簡單、直接的使用。在 Android 的 Gradle 中,Groovy 更多的是用于編寫腳本。如果會 Java,學習 Groovy 會比較簡單,甚至可以混寫 Java 和 Groovy 語法。

Groovy 相比 Java 語言來講,更加的方便靈活,更多的語法糖使編寫 Groovy 代碼更加的簡潔,而且在 Groovy 中具有函數式編程的思想。比如:Groovy 中非常重要的閉包 Closure 概念(類似于 C 語言中的函數指針),可以當做一個函數也執行,也可以當做某個函數的參數傳入到函數中去,也可以當做一個函數的返回值返回。

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

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

二. 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 
    }
}

上面代碼的執行輸出是:

> 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 中的數組區別并不大,也不過多的做介紹

  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 文檔

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,106評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,441評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,211評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,736評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,475評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,834評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,829評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,009評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,559評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,306評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,516評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,038評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,728評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,132評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,443評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,249評論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,484評論 2 379