學(xué)習(xí)Gradle,前前后后總結(jié)了一些內(nèi)容,然后整理出了一個(gè)系列,共計(jì)10篇文章,與大家分享:
- Groovy基本介紹
- 開始使用Gradle
- 自定義屬性
- 深入了解Task和構(gòu)建生命周期
- Gradle增量式構(gòu)建
- 掛接到構(gòu)建生命周期
- 編寫和使用自定義Task
- 依賴管理
- 多項(xiàng)目構(gòu)建
- 自定義Gradle插件
學(xué)習(xí)本系列前可以下載相關(guān)的github項(xiàng)目gradleLearnDemo。
地址:https://github.com/sososeen09/gradleLearnDemo
0 前言
Gradle腳本使用的是Groovy語言,Groovy也是基于JVM的一種動(dòng)態(tài)語言,基于Java并擴(kuò)展了Java語言。Groovy會(huì)使寫Java程序就要寫腳本一樣簡單,寫完就可以執(zhí)行,所以看起來也像是一門腳本語言。Groovy內(nèi)部會(huì)把代碼編譯為Java class文件然后啟動(dòng)虛擬機(jī)來執(zhí)行,這些過程,我們開發(fā)人員是不用管的。
Gradle是一種DSL,也即是 Domain Specific Language 領(lǐng)域特定語言。說白了DSL就是一種行話,這個(gè)語言在Gradle中可以識(shí)別,在其它地方就用不了了。
學(xué)習(xí)Gradle,我們不必要精通Groovy語言,但還是需要了解一些Groovy的基本知識(shí),比如def關(guān)鍵字、返回語句、字符串、集合、閉包等。下面,我們就來簡單介紹一下。
1 Groovy代碼的執(zhí)行
前面我們說了,Groovy很像是一門腳本語言,我們來看一下怎么回事。
創(chuàng)建一個(gè)HelloGroovy.groovy文件,里面就一行代碼
println 'hello groovy!'
然后執(zhí)行命令groovy HelloGroovy.groovy
,得到結(jié)果
hello groovy!
是不是很簡單,很像腳本語言。
2 Groovy中的字符串
Groovy 對字符串支持相當(dāng)強(qiáng)大,可以使用多種字符串,包括單引號、雙引號、三引號。
String str='hello groovy!'
String getStr(){
'hello groovy!'
}
String str1='hello'
String str2=' groovy!'
println 'hello groovy!'
println "hello groovy!"
println "$str"
println getStr()
println "${str1+str2}"
println 'hello $str2' //單引號,直接打印內(nèi)容
使用單引號會(huì)直接打印字符串的內(nèi)容,不會(huì)對美元$符號的內(nèi)容進(jìn)行轉(zhuǎn)義。使用雙引號的功能更加強(qiáng)大,字符串中使用美元符$后面可以跟字符串變量,如"$str"
,也可以跟表達(dá)式如 "${str1+str2}"
,如果跟表達(dá)式,記得要用{}括起來。
三引號用的比較少,可以支持字符串內(nèi)容換行,我們了解一下就行。
println ''' aa
bb
cc
'''
我們在getStr()方法中并沒有使用return語句,這是因?yàn)镚roovy默認(rèn)是把最后一行的執(zhí)行結(jié)果進(jìn)行返回。如果你需要返回的結(jié)果正好是最后一行,就可以省略return。
另外,在Groovy中,語句的最后的“;”
號是可以省略的。還有一點(diǎn)就是Groovy中在調(diào)用函數(shù)的時(shí)候可以不加括號,比如,println ("hello")
與 println "hello"
的意思是一樣的
3 def關(guān)鍵字
def關(guān)鍵字很像是Java中的Object,在定義變量或者方法的時(shí)候使用def,如果沒有指定具體的參數(shù)類型。在運(yùn)行階段Groovy會(huì)自動(dòng)判斷參數(shù)類型。
def a = 1, b = 2
def str = "hello"
println a + b
println str
實(shí)際上我們在定義變量的時(shí)候是可以省略def的,如
a = 1
b = 2
str = "hello"
但是,最好還是加上def,這是一種好的實(shí)踐。
你還可以在定義變量的時(shí)候,在def后面再加上具體的參數(shù)類型,如
def int a = 1
def String str = "hello"
使用def定義方法的返回值類型,可以返回任意類型。如果指定了具體的返回值類型,就要正確的返回,否則會(huì)報(bào)錯(cuò)。
4 集合
Groovy的基本類型與Java一樣。對于集合類型的數(shù)據(jù),List的具體實(shí)現(xiàn)是ArrayList。Map集合的具體實(shí)現(xiàn)是LinkedHashMap。
4.1 List
下面我們來簡單了解一下如果使用。List使用一個(gè) []中括號來括起來來表示的。
//定義一個(gè)List
def lists=['groovy','gradle','android']
//打印集合size
println lists.size
//打印集合中的數(shù)據(jù)
lists.each{
list->println list
}
取出集合中的數(shù)據(jù)直接用索引就可以了。比如:
assert lists[0]=='groovy'
對于集合中變量的存儲(chǔ),我們是不需要擔(dān)心數(shù)組越界的,如果索引超過當(dāng)前長度,List會(huì)自動(dòng)在該索引中添加元素。比如
lists[100]=100
println lists.size
println lists[99]
打印結(jié)果,會(huì)發(fā)現(xiàn)集合的size變?yōu)?01。index為99的集合數(shù)據(jù)為null。
4.2 Map
Map的表示就是用中括號[]括起來的 key:value形式。
def map=["key1":"hello","key2":"groovy","key3":true]
println map.size()
map.forEach{
key,value->
println "$key :$value"
}
結(jié)果是:
3
key1 :hello
key2 :groovy
key3 :true
獲取Map的元素
println map.'key1'
println map['key1']
添加元素
map.'key4'='android'
println map['key4']
5 Groovy的類
Groovy中的類與Java中的類的寫法類似,但是要更簡潔一些。
我們在Hello.groovy文件中寫一個(gè)HelloWorld類。
class HelloWorld{
String msg='hello world'
HelloWorld(){
}
HelloWorld(String msg){
this.msg=msg
}
void sayHello(){
println msg
}
}
def say={
new HelloWorld('hello').sayHello()
}
def getMsg={
new HelloWorld().msg
}
say()
println getMsg()
調(diào)用groovy Hello.groovy
命令執(zhí)行該腳本,結(jié)果如下:
hello
hello world
當(dāng)然了,我們也可以寫一個(gè)單獨(dú)的HelloWorld類,帶上包名,然后在其它地方導(dǎo)包使用,就像Java那樣。有關(guān)于Groovy類的使用,我們后面還會(huì)講到,這里就不贅述了。
總結(jié)一下Groovy的類相比Java的一些不同,或者說是優(yōu)化的一些地方:
- 表達(dá)式后面的分號是可選的
- 每個(gè)類、構(gòu)造方法和方法默認(rèn)是public的
- 在Groovy中,方法體中的最后一個(gè)表達(dá)式的值會(huì)被作為返回值。這意味著return語句是可選的
- Groovy編譯器自動(dòng)加上getter/setter方法,所以不需要自己去書寫
- 類的屬性可以通過點(diǎn)號來獲取,看起來好像它們在Java中是public的,在底層Groovy調(diào)用的是自動(dòng)生成的getter/setter方法。
6 閉包
閉包Closure,在Groovy中是很重要的一種數(shù)據(jù)類型。閉包實(shí)際上就是一段代碼塊,需要用{}包括起來。前面我們在講解一些例子的時(shí)候已經(jīng)用到了閉包,我們再來看一下閉包的結(jié)構(gòu)。
//定義一個(gè)閉包 ,記得要用{}包裹起來
def aClosure={
int a,int b-> //-> 箭頭前面代表的是參數(shù),后面是執(zhí)行語句
a+b //返回值
}
println aClosure(1,2)
結(jié)果為 3。
閉包的參數(shù)類型也可以不指定,在運(yùn)行期有Groovy自動(dòng)推斷,比如下面這個(gè)例子,執(zhí)行起來也是沒有問題的
def bClosure={
a,b->
a+b
}
println bClosure(1,2)
閉包也可以沒有參數(shù)
如:
def aa={
println "this is a Closure"
}
aa()
總結(jié)一下,閉包的類型有
1. def closureNama ={params -> code}
2. def closureName= {code} 沒有參數(shù)的時(shí)候就沒有箭頭 ->
閉包的調(diào)用有兩種方式
1. 閉包對象.call(參數(shù))
2. 閉包對象(參數(shù))
如
aClosure(1,2)
aClosure.call(1,2)
需要注意一點(diǎn),閉包如果沒有參數(shù)的話,其隱含了一個(gè)參數(shù)是 it
。
和this的作用類似,代表的是傳入閉包的參數(shù)。比如:
def sayHello={"hello ${it}"}
println sayHello("Jim")
等同于
def sayHello={it->"hello ${it}"}
當(dāng)然了,如果閉包顯示的指明了無參數(shù),則在調(diào)用閉包的時(shí)候不能傳參數(shù),否則會(huì)報(bào)錯(cuò)。如
def noParams={->println "noParams"}
noParams();
//下面的代碼執(zhí)行會(huì)報(bào)錯(cuò)
//noParams(1)
閉包返回值
閉包總是會(huì)返回一個(gè)值。返回值是閉包的最后一條語句的值(如果沒有顯式的return語句),或者是可執(zhí)行的return 語句的值。如果閉包的最后一條語句沒有值就返回null。如之前舉得Hello.groovy中的例子:
def getMsg={
new HelloWorld().msg
}
閉包作為方法參數(shù)
閉包也可以作為方法參數(shù),如:
int increment(Closure closure,int count){
closure()+count
}
//斷言,如果為true就正常執(zhí)行,如果為false,就會(huì)報(bào)錯(cuò)
assert increment({1+1},1)==3
閉包委托
閉包代碼是在委托的閉包上執(zhí)行。默認(rèn)的,這個(gè)委托就是閉包的所有者。比如你在Groovy腳本中定義了一個(gè)閉包,那么所有者就是一個(gè)groovy.lang.Script實(shí)例。閉包的隱式變量delegate 允許你重新定義默認(rèn)的所有者。
例如:
class Test {
def x = 30
def y = 40
def run() {
def data = [ x: 10, y: 20 ]
def cl = {
y = x + y
}
cl.delegate = data
cl.resolveStrategy = Closure.DELEGATE_FIRST
cl()
assert x == 30
assert y == 40
assert data == [x:10, y:30]
}
}
new Test().run()
上面例子中閉包c(diǎn)1的委托變?yōu)閐ata,閉包的resolveStrategy在默認(rèn)情況下是OWNER_FIRST,即它會(huì)先查找閉包的owner(在本例中指的就是Test對象本身),如果owner存在,則在owner上執(zhí)行閉包中的代碼。這里我們將其設(shè)置成了DELEGATE_FIRST,即該閉包會(huì)首先查找delegate(本例中即data),如果找不到再去找owner。resolveStrategy還有其它的一些情況,具體的可以查看文檔中的例子,相信當(dāng)你看到這些例子后,會(huì)對閉包委托有一個(gè)清晰的認(rèn)識(shí)。
7 總結(jié)
限于篇幅和本系列的主題,本文簡單介紹了Groovy的一些語法和數(shù)據(jù)結(jié)構(gòu),這對于學(xué)習(xí)Gradle會(huì)有一些幫助。在后面Gradle的學(xué)習(xí)過程中,如果對Groovy的一些Api不熟悉可以查看Groovy的Api文檔,我們沒必要死記硬背這個(gè)Api,掌握學(xué)習(xí)的方法更加重要,對嗎?
下一篇,我們就正式進(jìn)入Gradle部分的學(xué)習(xí)了。