最近在學習 Android 中 Gradle 相關的知識,如果想學好 Gradle,必要的 Groovy 基礎是不可少的。Groovy 語言的知識也是非常多的,如果只是想在 Android Gradle 這個範圍內使用 Groovy,會 Groovy 的基礎即可,Groovy 語言文件。
一. 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 變數
- Groovy 中宣告的變數,預設的修飾符是 public 的
- Groovy 中宣告變數時,如果一行只宣告一個變數則可以省略末尾的
;
,但是如果一行宣告瞭多個變數,變數與變數之間則不可以省略;
- 在 Groovy 中宣告變數,也可以使用關鍵字
def
,def
只是宣告瞭一個變數,變數的實際型別根據該變數的物件決定。def
和 JavaScript 中的val
有點像,從def
可以看出 Groovy 也是一門動態語言 - Groovy 中字串
String
,可以使用單引號 'String',也可以使用雙引號 "String" - 在 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
- 因為在 Groovy 中沒有定義任何集合類,所以 Groovy 中的 List 使用的是 JDK 中的 java.util.List
- 在 Groovy 中的一個 List 中可以新增多種型別的物件元素
- 建立 List 物件使用
[]
,而不是 Java 中的{}
,防止和 Groovy 中的閉包 Closure {}
混淆 - 可以通過
[index]
的方式修改和訪問 List 中的元素 - 可以通過
<<
向 List 中新增元素,<<
實際是leftShift()
方法 - 可以通過負數,從後向前訪問 List 中的元素,比如
[-1]
表示最後一個元素 - 可以通過
[index1, index2]
同時訪問 List 中的多個元素,返回結果仍是一個List - 可以通過
[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 中的陣列區別並不大,也不過多的做介紹
- Groovy 中的陣列使用
[]
初始化,並不使用{}
,防止和 Groovy 中的閉包 Closure {}
混淆 - 陣列不支援
<<
向 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
- Groovy 中的 Map 是以
:
作為 key 和 value 的連線,並且以,
做為每一項的分隔符的 - Map 中的 key 既可以是字串也可以是阿拉伯數字
- 可以通過
[key]
和.key
的形式訪問或向 map 中賦值,訪問的時候如果不存在該key
,則會返回null
- 如果以變數作為 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 區別並不大,主要有以下幾個區別
- 如果類、方法沒有修飾符的話,預設是
public
修飾符的 - 如果類中的變數
fields
沒有被修飾符修飾的話,會自動成為一個properties
,properties
是公有的,並且會自動生成該properties
的 setter 和 getter 方法 - 在 Java 中,檔名和主類的名稱必須一致,但是 Groovy 中並沒有這個限制,且在一個 Groovy 檔案中可以出現多個
public
的類 - 在一個 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 中的函式並沒有太大的區別
- 函式一定會有返回值,如果沒有顯示的使用
return
返回值的話,函式的最後一行語句的執行結果作為值返回,可能返回值是個null
- 如果函式有引數,呼叫函式的時候,可以省略函式的括號,函式名和引數之間需要用空格間隔;如果函式沒有引數,呼叫函式的時候就不能省略括號
- 函式內不可以訪問函式外的變數
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 會有莫大的幫助
- 閉包
closure
的定義如下,其中[closureParameters ->]
作為引數部分,是可以省略的
{ [closureParameters -> ] statements }
複製程式碼
closure
其實是 Groovy 中groovy.lang.Closure
的一個類- 閉包
closure
可以訪問閉包之外的變數 - 閉包
closure
可以有三種呼叫方式,如下程式碼所示 - 閉包
closure
的引數可以省略,預設是有個it
引數的 - 閉包
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 文件