Groovy概述
Groovy是Apache 旗下的一種基于JVM的面向?qū)ο缶幊陶Z言纸型,既可以用于面向?qū)ο缶幊檀希部梢杂米骷兇獾哪_本語言永品。在語言的設(shè)計(jì)上它吸納了Python遭京、Ruby 和 Smalltalk 語言的優(yōu)秀特性胃惜,比如動(dòng)態(tài)類型轉(zhuǎn)換泞莉、閉包和元編程支持。
Groovy與 Java可以很好的互相調(diào)用并結(jié)合編程 船殉,比如在寫 Groovy 的時(shí)候忘記了語法可以直接按Java的語法繼續(xù)寫鲫趁,也可以在 Java 中調(diào)用 Groovy 腳本。比起Java捺弦,Groovy語法更加的靈活和簡潔饮寞,可以用更少的代碼來實(shí)現(xiàn)Java實(shí)現(xiàn)的同樣功能孝扛。
1.變量
Groovy中用def關(guān)鍵字來定義變量列吼,可以不指定變量的類型,默認(rèn)訪問修飾符是public苦始。
task variable <<{
def a=10
def float b=10.5f
def c="Haha"
println(a)
println(b)
println(c)
}
2.方法
方法使用返回類型或def關(guān)鍵字定義寞钥,方法可以接收任意數(shù)量的參數(shù),這些參數(shù)可以不申明類型陌选,如果不提供可見性修飾符理郑,則該方法為public。
(1)用def關(guān)鍵字來定義方法
task method << {
def result1=add(2,4)
def result2=sub(4,2)
println "result1:"+result1+",result2:"+result2
printStr()
}
def add(int a,int b)
{
return a+b
}
def sub(a,b)
{
return a-b
}
def printStr()
{
println "Print Something"
}
(2)如果指定了方法返回類型咨油,可以不需要def關(guān)鍵字來定義方法您炉。
task method << {
def result1=add(2,4)
def result2=sub 4,2
println "result1:"+result1+",result2:"+result2
}
int add(int a,int b)
{
return a+b
}
int sub(a,b)
{
return a-b
}
(3)如果不使用return ,方法的返回值為最后一行代碼的執(zhí)行結(jié)果役电。
task method << {
def result1=add(2,4)
def result2=sub 4,2
println "result1:"+result1+",result2:"+result2
}
int add(int a,int b)
{
a+b
}
int sub(a,b)
{
a-b
}
從上面的幾段代碼可以看出赚爵,Groovy代碼可以省略的地方有如下幾處:
1.語句后面的分號可以省略。
2.方法的括號可以省略法瑟,比如注釋1和注釋3處冀膝。
3.參數(shù)類型可以省略,比如注釋2處霎挟。
4.return可以省略掉窝剖,比如注釋4處。
3.類
Groovy類非常類似于Java類酥夭。
task testClass << {
def p=new Person()
p.increaseAge 10
println "Age:"+p.age
}
class Person{
String name
Integer age=10
def increaseAge(Integer years)
{
this.age+=years
}
}
Groovy類與Java類有以下的區(qū)別:
默認(rèn)類的修飾符為public赐纱。
沒有可見性修飾符的字段會(huì)自動(dòng)生成對應(yīng)的setter和getter方法。
類不需要與它的源文件有相同的名稱熬北,但還是建議采用相同的名稱疙描。
4.語句
(1)斷言
Groovy斷言和Java斷言不同,它一直處于開啟狀態(tài)蒜埋,是進(jìn)行單元測試的首選方式淫痰。
task testAssert << {
assert 1+2==6
}
運(yùn)行結(jié)果:
當(dāng)斷言的條件為false時(shí),程序會(huì)拋出異常整份,不再執(zhí)行下面的代碼待错,從輸出可以很清晰的看到發(fā)生錯(cuò)誤的地方籽孙。
(2)for循環(huán)
Groovy支持Java的for(int i=0;i<N;i++)和for(int i :array)形式的循環(huán)語句,另外還支持for in loop形式火俄,支持遍歷范圍犯建、列表、Map瓜客、數(shù)組和字符串等多種類型适瓦。
task testFor << {
//遍歷范圍
def x=0
for(i in 0..3)
{
x+=i
}
assert x==6
//遍歷列表
x=0
for(i in [0,1,2,3])
{
x+=i
}
assert x==6
//遍歷Map中的值
def map=['a':1,'b':2,'c':3]
x=0
for(v in map.values())
{
x+=v
}
assert x==6
}
(3)Switch語句
Groovy中的Switch語句不僅兼容Java代碼,還可以處理更多類型的case表達(dá)式谱仪。
task testSwitch << {
def x=16
def result=""
switch(x)
{
case "ok":
result="found ok"
break
case [1,2,3,'List']:
result="list"
break
case 10..19:
result="range"
break
case Integer:
result="integer"
break
default:
result="default"
break
}
assert result=="integer"
}
case表達(dá)式可以是字符串玻熙、列表、范圍疯攒、Integer等等嗦随,因?yàn)槠颍@里只列出了一小部分敬尺。
5.數(shù)據(jù)類型
Groovy中的數(shù)據(jù)類型主要有以下幾種:
Java中的基本數(shù)據(jù)類型
Groovy中的容器類
閉包
(1) 字符串
Groovy中的基本數(shù)據(jù)類型和Java大同小異枚尼,這里主要介紹下字符串類型。在Groovy種有兩種字符串類型砂吞,普通字符串String(java.lang.String)和插值字符串GString(groovy.lang.GString)署恍。
單引號字符串
在Groovy中單引號字符串和雙引號字符串都可以定義一個(gè)字符串常量,只不過單引號字符串不支持插值蜻直。
'Android進(jìn)階解密'
雙引號字符串
要想插值可以使用雙引號字符串盯质,插值指的是替換字符串中的占位符,占位符表達(dá)式為為前綴袭蝗。
def name = 'Android進(jìn)階之光'
println "hello ${name}"
println "hello $name"
三引號字符串
三引號字符串可以保留文本的換行和縮進(jìn)格式唤殴,不支持插值.
task method <<{
def name = '''Android進(jìn)階之光
Android進(jìn)階解密
Android進(jìn)階?'''
println name
}
打印結(jié)果為:
Android進(jìn)階之光
Android進(jìn)階解密
Android進(jìn)階到腥?
GString
String是不可變的朵逝,GString卻是可變的,GString和String即使有相同的字面量乡范,它們的hashCodes的值也可能不同配名,因此應(yīng)該避免使用使用GString作為Map的key。
assert "one: ${1}".hashCode() != "one: 1".hashCode()
當(dāng)雙引號字符串中包含插值表達(dá)式時(shí)晋辆,字符串類型為GString渠脉,因此上面的斷言為true。
(2)List
Groovy沒有定義自己的集合類瓶佳,它在Java集合類的基礎(chǔ)上進(jìn)行了增強(qiáng)和簡化芋膘。Groovy的List對應(yīng)Java中的List接口,默認(rèn)的實(shí)現(xiàn)類為Java中的ArrayList。
def number = [1, 2, 3]
assert number instanceof List
def linkedList = [1, 2, 3] as LinkedList
assert linkedList instanceof java.util.LinkedList
可以使用as操作符來顯式指定List的實(shí)現(xiàn)類為java.util.LinkedList为朋。
獲取元素同樣要比Java要簡潔些臂拓,使用[]來獲取List中具有正索引或負(fù)索引的元素。
task method <<{
def number = [1, 2, 3, 4]
assert number [1] == 2
assert number [-1] == 4 //1
number << 5 //2
assert number [4] == 5
assert number [-1] == 5
}
注釋1處的索引-1是列表末尾的第一個(gè)元素习寸。注釋2處使用<<運(yùn)算符在列表末尾追加一個(gè)元素胶惰。
(3) Map
創(chuàng)建Map同樣使用[],需要同時(shí)指定鍵和值霞溪,默認(rèn)的實(shí)現(xiàn)類為java.util.LinkedHashMap孵滞。
def name = [one: '魏無羨', two: '楊影楓', three: '張無忌']
assert name['one'] == '魏無羨'
assert name.two == '楊影楓'
Map還有一個(gè)鍵關(guān)聯(lián)的問題:
def key = 'name'
def person = [key: '魏無羨'] //1
assert person.containsKey('key')
person = [(key): '魏無羨'] //2
assert person.containsKey('name')
注釋1處魏無羨的鍵值是key這個(gè)字符串,而不是key變量的值 name鸯匹。如果想要以key變量的值為鍵值坊饶,需要像注釋2處一樣使用(key),用來告訴解析器我們傳遞的是一個(gè)變量忽你,而不是定義一個(gè)字符串鍵值幼东。
(4)閉包
Groovy中的閉包是一個(gè)開放的臂容、匿名的科雳、可以接受參數(shù)和返回值的代碼塊。
定義閉包
閉包的定義遵循以下語法:
{ [closureParameters -> ] statements }
閉包分為兩個(gè)部分脓杉,分別是參數(shù)列表部分[closureParameters -> ]和語句部分 statements 糟秘。
參數(shù)列表部分是可選的,如果閉包只有一個(gè)參數(shù)球散,參數(shù)名是可選的尿赚,Groovy會(huì)隱式指定it作為參數(shù)名,如下所示蕉堰。
{ println it } //使用隱式參數(shù)it的閉包
當(dāng)需要指定參數(shù)列表時(shí)凌净,需要->將參數(shù)列表和閉包體相分離。
{ it -> println it } //it是一個(gè)顯示參數(shù)
{ String a, String b ->
println "${a} is a $屋讶"
}
閉包是groovy.lang.Cloush類的一個(gè)實(shí)例冰寻,這使得閉包可以賦值給變量或字段,如下所示皿渗。
//將閉包賦值給一個(gè)變量
def println ={ it -> println it }
assert println instanceof Closure
//將閉包賦值給Closure類型變量
Closure do= { println 'do!' }
調(diào)用閉包
閉包既可以當(dāng)做方法來調(diào)用斩芭,也可以顯示調(diào)用call方法。
def code = { 123 }
assert code() == 123 //閉包當(dāng)做方法調(diào)用
assert code.call() == 123 //顯示調(diào)用call方法
def isOddNumber = { int i -> i%2 != 0 }
assert isOddNumber(3) == true //調(diào)用帶參數(shù)的閉包
6.I/O操作
Groovy的 I/O 操作要比Java的更為的簡潔乐疆。
(1)文件讀取
可以先建立一個(gè)txt文件划乖,在其中輸入一些內(nèi)容,然后用來讀取挤土。
task testReadFile << {
def filePath="E:/test.txt"
def file=new File(filePath)
file.eachLine{
println it
}
}
可以看出Groovy的文件讀取是很簡潔的琴庵,還可以更簡潔些:
def filePath = "D:/Android/name.txt"
def file = new File(filePath) ;
println file.text
(2)文件寫入
文件寫入也是比較簡潔的。
task testWriteFile << {
def fileName="E:/test.txt"
def file=new File(fileName)
file.withPrintWriter{
it.println("Kobe")
it.println("James")
}
}
7.其他
(1)asType
asType用于類型轉(zhuǎn)換。
task testAsType << {
String a='23'
int b=a as int
def c=a.asType(Integer)
assert c instanceof java.lang.Integer
}
(2)判斷是否為真
if (name != null && name.length > 0) {}
替換為
if (name) {}
(3)安全取值
在Java中迷殿,要安全獲取某個(gè)對象的值可能需要大量的if語句來判空:
if (school != null) {
if (school.getStudent() != null) {
if (school.getStudent().getName() != null) {
System.out.println(school.getStudent().getName());
}
}
}
Groovy中可以使用尉桩?.來安全的取值:
println school?.student?.name
(4)with操作符
對同一個(gè)對象的屬性進(jìn)行賦值時(shí),可以這么做:
task method <<{
Person p = new Person()
p.name = "楊影楓"
p.age = 19
p.sex = "男"
println p.name
}
class Person {
String name
Integer age
String sex
}
使用with來進(jìn)行簡化:
Person p = new Person()
p.with {
name = "楊影楓"
age= 19
sex= "男"
}
println p.name