Groovy是基于JVM虛擬機的一種動態(tài)語言,它的語法和Java非常相似鞋喇,由Java入門Groovy声滥,基本上沒有任何障礙。Groovy完全兼容Java确徙,又在此基礎上增加了很多動態(tài)類型和靈活的特性醒串,比如支持閉包,支持DSL鄙皇,可以說它是一門非常靈活的動態(tài)腳本語言芜赌。
Groovy的特性雖然不多,但也有一些伴逸,我們不可能在這里都講完缠沈,這也不是這本書的初衷,在這里我挑一些和Gradle有關的知識講错蝴,讓大家很快的入門Groovy洲愤,并且能看懂這門腳本語言,知道在Gradle為什么這么寫顷锰。其次是每個Gradle的build腳本文件都是一個Groovy腳本文件柬赐,你可以在里面寫任何符合Groovy的代碼,比如定義類官紫,生命函數(shù)肛宋,定義變量等等,而Groovy又完全兼容Java束世,這就意味著你可以在build腳本文件里寫任何的Java代碼酝陈,非常靈活方便。
字符串
字符串毁涉,每一門語言都會有對字符串的處理沉帮,Java相對要稍微復雜一些,限制比較多贫堰,相比而言穆壕,Groovy非常方便,比如字符串的運算其屏、求值粱檀、正則等等。
從現(xiàn)在開始我們算是正式的介紹Groovy了漫玄,在此之前我們先要知道,在Groovy中,分號不是必須的睦优。相信很多用Java的朋友都習慣了渗常,沒一行的結束必須有分號,但是Groovy每這個強制規(guī)定汗盘,所以你看到的Gradle腳本很多都沒有分號皱碘,其實這個是Groovy的特性,而不是Gradle的隐孽。沒有分號的時候癌椿,我們閱讀的時候沒一行默認為有分號就好了。
在Groovy中菱阵,單引號和雙引號都可以定義一個字符串常量(Java里單引號定義一個字符)踢俄,不同的是單引號標記的是純粹的字符串常量,而不是對字符串里的表達式做運算晴及,但是雙引號可以都办。
task printStringClass << {
defstr1 = '單引號'
defstr2 = "雙引號"
println"單引號定義的字符串類型:"+str1.getClass().name
println"雙引號定義的字符串類型:"+str2.getClass().name
}
./gradlew printStringClass
運行后我們能可以看到輸出:
單引號定義的字符串類型:java.lang.String
雙引號定義的字符串類型:java.lang.String
不管是單引號定義的還是雙引號定義的都是String類型。
剛剛我們講了單引號不能對字符串里的表達式做運算虑稼,下面我們看個例子:
task printStringVar << {
defname = "張三"
println'單引號的變量計算:${name}'
println"單引號的變量計算:${name}"}
./gradlew printStringVar
運行后輸出:
單引號的變量計算:${name}單引號的變量計算:張三
可以看到琳钉,雙引號標記的輸出了我們想要的結果,但是單引號沒有蛛倦,所以大家可以記住了歌懒,單引號沒有運算的能力,它里面的所有都是常量字符串溯壶。
雙引號可以直接進行表達式計算的這個能力非常好用及皂,我們可以用這種方式進行字符串鏈接運算,再也不用Java中繁瑣的+號了茸塞。記住這個嵌套的規(guī)則躲庄,一個美元符號緊跟著一對花括號,花括號里放表達式钾虐,比如${name}
,${1+1}
等等噪窘,只有一個變量的時候可以省略花括號,比如$name
效扫。
集合
集合倔监,也是我們在Java中經(jīng)常用到的,Groovy完全兼容了Java的集合菌仁,并且進行了擴展浩习,使得生命一個集合,迭代一個集合济丘、查找集合的元素等等操作變得非常容易谱秽。常見的集合有List
洽蛀、Set
、Map
和Queue
,這里我們只介紹常用的List
和Map
。
List
在Java里槽华,定義一個List稿黄,需要New一個實現(xiàn)了List接口的類,太繁瑣,在Groovy中則非常簡單。
task printList << {
def numList =[1,2,3,4,5,6];
println numList.getClass().name
}
可以通過輸出看到numList是一個ArrayList類型。
定義好集合了疯淫,怎么訪問它里面的元素呢,像Java一樣戳玫,使用get方法熙掺?太Low了,Groovy提供了非常簡便的方法量九。
task printList << {
def numList =[1,2,3,4,5,6];
println numList.getClass().name
println numList[1]//訪問第二個元素
println numList[-1]//訪問最后一個元素
println numList[-2]//訪問倒數(shù)第二個元素
println numList[1..3]//訪問第二個到第四個元素
}
Groovy提供下標索引的方式訪問适掰,就像數(shù)組一樣,除此之外荠列,還提供了負下標和范圍索引类浪。負下標索引代表從右邊開始數(shù),-1就代表從右側(cè)數(shù)第一個肌似,-2代表右側(cè)數(shù)第二個费就,以此類推;1..3這種是一個范圍索引川队,中間用兩個.分開力细,這個會經(jīng)常遇到。
除了訪問方便之外固额,Groovy還為List提供了非常方便的迭代操作眠蚂,這就是each方法,該方法接受一個閉包作為參數(shù)斗躏,可以訪問List里的每個元素逝慧。
task printList << {
def numList =[1,2,3,4,5,6];
println numList.getClass().name
println numList[1]//訪問第二個元素
println numList[-1]//訪問最后一個元素
println numList[-2]//訪問倒數(shù)第二個元素
println numList[1..3]//f訪問第二個到第四個元素
numList.each {
println it
}
}
it變量就是正在迭代的元素,這里有閉包的知識啄糙,我們可以先這么記住笛臣,后面詳細講。
Map
Map和List很像隧饼,只不過它的值是一個K:V鍵值對沈堡,所以在Groovy中Map的定義也非常簡單。
task printlnMap << {
def map1 =['width':1024,'height':768]
println map1.getClass().name
}
訪問也非常靈活容易燕雁,采用map[key]或者map.key的方式都可以诞丽。
task printlnMap << {
def map1 =['width':1024,'height':768]
println map1.getClass().name
println map1['width']
println map1.height
}
這兩種方式都能快速的取出指定key的值鲸拥,怎么樣,比Java方便的多吧率拒。
對于Map的迭代崩泡,當然也少不了each方法,只不過被迭代的元素是一個Map.Entry的實例猬膨。
task printlnMap << {
def map1 =['width':1024,'height':768]
println map1.getClass().name
println map1['width']
println map1.height
map1.each {
println "Key:${it.key},Value:${it.value}"
}
}
對于集合,Groovy還提供了諸如collect呛伴、find勃痴、findAll等便捷的方法,有興趣的朋友可以找相關文檔看一下热康,這里就不一一講了沛申。
方法
方法大家都不陌生,這里特別用一節(jié)講的目的主要是講Groovy方法和Java的不同姐军,然后我們才能看明白我們的Gradle腳本里的代碼铁材,突然發(fā)現(xiàn),原來這是一個方法調(diào)用稗刃俊著觉!
括號是可以省略的
我們在Java中調(diào)用一個方法都是invokeMethod(parm1,parm2),非常規(guī)范惊暴,Java就是這么中規(guī)中矩的語言饼丘,在Groovy中就要靈活的多,可以省略()變成這樣invokeMethod parm1辽话,parm2 是不是覺得非常簡潔肄鸽,這在定義DSL的時候非常有用,書寫也非常方便油啤。
task invokeMethod << {
method1(1,2)
method1 1,2
}
def method1(int a,int b){
println a+b
}
上例中這兩種調(diào)用方式的結果是一樣的典徘,有沒有覺得第二種更簡潔的多,Gradle中的方法調(diào)用都是這種寫法益咬。
return是可以不寫的
在Groovy中逮诲,我們定義有返回值的方法時,return語句不是必須的础废,當沒有return的時候汛骂,Groovy會把方法執(zhí)行過程中的最后一句代碼作為其返回值。
task printMethodReturn << {
def add1 = method2 1,2
def add2 = method2 5,3
println "add1:${add1},add2:${add2}"
}
def method2(int a,int b){
if(a>b){
a
}else{
b
}
}
```groovy
執(zhí)行`./gradlew printMethodReturn`后可以看到輸出:
```bash
add1:2,add2:5
從例子中可以看出评腺,當a作為最后一行被執(zhí)行的代碼時帘瞭,a就是該方法的返回值,反之則是b蒿讥。
代碼塊是可以作為參數(shù)傳遞的
代碼塊—一段被花括號包圍的代碼蝶念,其實就是我們后面要將的閉包抛腕,Groovy是允許其作為參數(shù)傳遞的,但是結合這我們上面方法的特性媒殉,最后的基于閉包的方法調(diào)用就會非常優(yōu)雅担敌、易讀。以我們的集合的each方法為例廷蓉,它接受的參數(shù)其實就是一個閉包全封。
//基于死板的寫法其實是這樣
numList.each({println it})
//我們格式化一下,是不是好看一些
numList.each({
println it
})
//好看一些桃犬,Groovy規(guī)定刹悴,如果方法的最后一個參數(shù)是閉包,可以放到方法外面
numList.each(){
println it
}
//然后方法可以省略攒暇,就變成我們經(jīng)惩猎龋看到的啦
numList.each {
println it
}
了解了這個演進方式,你再看到類似的這樣的寫法就明白了形用,原來是一個方法調(diào)用就轧,以此類推,你也知道怎么定義一個方法田度,讓別人這么調(diào)用妒御。
JavaBean
JavaBean是一個非常好的概念,你現(xiàn)在看到的組件化每币、插件化携丁、配置集成等都是基于JavaBean。在Java中為了訪問和修改JavaBean的屬性兰怠,我們不得不重復的生成getter/setter方法梦鉴,并且使用他們,太麻煩揭保,太繁瑣肥橙,這在Groovy中得到很大的改善。
task helloJavaBean << {
Person p = new Person()
println "名字是:${p.name}"
p.name = "張三"
println "名字是:${p.name}"
}
class Person {
private String name
}
在沒有給name屬性賦值的時候秸侣,輸出是null存筏,賦值后,輸出的就是“張三”了味榛,通過上面例子椭坚,我們發(fā)現(xiàn),我們在Groovy可以非常容易的訪問和修改JavaBean的屬性值搏色,而不用借助getter/setter方法善茎,這是因為Groovy都幫我們搞定了。
在Groovy中频轿,并不是一定要定義成員變量垂涯,才能作為類的屬性訪問烁焙,我們直接getter/setter方法,也一樣可以當做屬性訪問耕赘。
task helloJavaBean << {
Person p = new Person()
println "名字是:${p.name}"
p.name = "張三"
println "名字是:${p.name}"
println "年齡是:${p.age}"}
class Person {
private String name
public int getAge(){
12
}
}
通過上面的例子我們可以發(fā)現(xiàn)骄蝇,我并沒有定義一個age的成員變量,但是我一樣可以通過p.age獲取到該值操骡,這是因為我們定義了getAge()方法九火。那么這時候我們能不能修改age的值呢?答案是不能的当娱,因為我們沒有為其定義setter方法吃既。
在Gradle中你會見到很多這種寫法,你開始以為這是該對象的一個屬性跨细,其實只是因為該對象里定義了相應的getter/setter方法而已。