原文發於微信公眾號 jzman-blog,歡迎關注交流。
上一篇學習了 Gradle 的入門知識,Gradle 基於 Groovy,今天學習一下 Groovy 的基礎知識,Groovy 是基於 JVM 虛擬機的一種動態語言,語法與 Java 語法類似,Groovy 完全兼容 Java,每個 Gradle 文件都是一個 Groovy 腳本文件,Gradle 文件基於 Groovy 語法,而 Groovy 又兼容 Java,故可以在 Gradle 文件中寫 Java 代碼,在此基礎上增加了很多新特性,如支持閉包、DSL等,可以說 Groovy 是一門非常靈活的動態腳本語言,閱讀本文之前可以先閱讀下面這篇文章:
下面針對 Gradle 來學習一下 Groovy 的一些基礎知識。
- 字符串
- 集合
- 方法
- JavaBean
- 關於閉包
字符串
說一個 Groovy 的特性,在 Groovy 中分號不是必須的,其單引號是雙引號都定義的是一個字符串常量,不同之處是單引號是純粹的字符串常量,不會對該字符串里面的表達式做運算,而使用雙引號定義的字符串常量可以使用合法表達式做相關運算,測試代碼如下:
task stringTest{
//使用def關鍵字定義變量,
def str1 = "雙引號"
def str2 = '單引號'
println "雙引號定義的字符串:"+str1
println "雙引號定義的字符串:"+str1.class
println "單引號定義的字符串:"+str2
//變量動態變化
str1 = true;
println "雙引號定義的字符串:"+str1.class
//使用$運算符
println "雙引號定義的字符串:${str1}"
//只有一個變量的時候可以省去中括號
println "雙引號定義的字符串:$str1"
//單引號定義的字符串不能使用表達式進行運算
println '單引號定義的字符串:$str2'
}
下面是執行結果,參考如下:
PS E:\Gradle\study\Groovy> gradle stringTest
> Configure project :
雙引號定義的字符串:雙引號
雙引號定義的字符串:class java.lang.String
單引號定義的字符串:單引號
雙引號定義的字符串:class java.lang.Boolean
雙引號定義的字符串:true
雙引號定義的字符串:true
單引號定義的字符串:$str2
BUILD SUCCESSFUL in 1s
集合
Groovy 中也有集合的概念,主要看一下常用的 List、Map,下面將對 List 和 Map 常用操作進行介紹。
那么如何在 Groovy 中定義 List 呢,Groovy 中的 List 的定義方式類似於 Java 中的數組,具體操作參考下面代碼:
task list{
//定義List
def list = [1,2,3,4,5,6];
def weekList = ['星期一','星期二','星期三','星期四','星期五','星期六','星期日'];
println "list的類型:"+list.class
println "weekList的類型:"+weekList.class
//訪問集合里面的元素
println '第一個元素:'+list[0]//訪問第一個元素
println '第二個元素:'+list[1]//訪問第二個元素,以此類推
println '最后一個元素:'+list[-1]//訪問最后一個元素
println '倒數第二個元素:'+list[-2]//訪問倒數第二個元素,以此類推
println '某個范圍內元素:'+list[2..4]//訪問某個范圍內元素,以此類推
//使用each遍歷集合中的元素
weekList.each{
//使用it作為迭代的元素變量,不能寫錯喔
println it
}
}
下面是上述代碼的執行結果,參考如下:
PS E:\Gradle\study\Groovy\ListMap> gradle list
> Configure project :
list的類型:class java.util.ArrayList
weekList的類型:class java.util.ArrayList
第一個元素:1
第二個元素:2
最后一個元素:6
倒數第二個元素:5
某個范圍內元素:[3, 4, 5]
星期一
星期二
星期三
星期四
星期五
星期六
星期日
BUILD SUCCESSFUL in 2s
那么如何在 Groovy 中定義 Map 呢,Groovy 中的 Map 當然也是鍵值對,具體定義及操作參考下面代碼:
task map{
//定義Map
def map = ['name':'Groovy', 'age':10];
println "map的類型:"+map.getClass().name;
//訪問Map里面的元素
println map.name;
println map['name'];
//遍歷Map中的元素
map.each{
println "Key:${it.key},value:${it.value}"
}
}
下面是上述代碼的執行結果,參考如下:
PS E:\Gradle\study\Groovy\ListMap> gradle map
> Configure project :
map的類型:java.util.LinkedHashMap
Groovy
Groovy
Key:name,value:Groovy
Key:age,value:10
BUILD SUCCESSFUL in 2s
關於 Groovy 的集合就了解這么多。
方法
Groovy 中的方法和 Java 中的方法類似,只是寫法上更加靈活,Groovy 中 return 不是必須的,在不寫 return 的時候,Groovy 會將最后一句代碼作為該方法的返回值。代碼塊指的是一段被花括號包圍的代碼,Groovy 中可將代碼塊作為一個參數進行傳遞,可以參考前面關於集合的遍歷部分,參考代碼如下:
task method{
//方法調用
methodA(1, 2)
methodA 1, 2
//獲取方法返回的結果
def a = methodA 10, 20
println '獲取方法返回的結果:'+a
//代碼塊作為參數傳遞
def list = [1,2,3,4,5];
list.each(
//閉包參數
{
// println it
}
)
//Groovy規定,如果方法的最后一個參數是閉包,可以直接放到方法外面
list.each(){
// println it
}
//簡寫方式
list.each{
println it
}
}
//方法的定義
def methodA(int a, int b){
println a + b
//Groovy中return語句不是必須的,默認將最后一句代碼的結果作為返回值
a + b
}
下面是上述代碼參考如下:
PS E:\Gradle\study\Groovy\Method> gradle method
> Configure project :
3
3
30
獲取方法返回的結果:30
1
2
3
4
5
BUILD SUCCESSFUL in 2s
JavaBean
Groovy 中的 JavaBean 相較 Java 中的比較靈活,可以直接使用 javaBean.屬性的方式獲取和修改 JavaBean 的屬性值,無需使用相應的 Getter、Setter 方法,直接看代碼:
task javaBean{
//Groovy中定義JavaBean
Student student = new Student()
student.name = "Groovy"
student.age = 10
student.setName("Gradle")
println "名字是:"+student.name
//不能調用Getter方法獲取值
// println "名字是:"+student.getName
println "年齡是:${student.age}"
println "分數是:"+student.score
}
class Student{
private String name
private int age
//定義的Getter方法所對應的屬性可以直接調用
public String getScore(){
100
}
//屬性的Getter、Setter方法
public String setName(String name){
this.name = name
}
public void getName(){
name
}
}
下面是上述代碼的執行結果:
PS E:\Gradle\study\Groovy\JavaBean> gradle javaBean
> Configure project :
名字是:Gradle
年齡是:10
分數是:100
BUILD SUCCESSFUL in 2s
閉包
閉包是大多數腳本語言具有的一個特性,如 JavaScript、Groovy 等,閉包就是一個使用花括號包圍的代碼塊,下面來學習 Groovy 中的閉包,主要有兩部分:閉包及閉包參數傳遞和閉包委托。
閉包及其參數傳遞
下面來看一下如何定義一個閉包以及相關參數的傳遞,直接上代碼:
task closure{
//自定義閉包的執行
mEach{
println it
}
//向閉包傳遞參數
mEachWithParams{m,n -> //m,n ->將閉包的參數和主體區分離開來
println "${m} is ${n}"
}
}
//1.定義一個方法,參數closure用於接收閉包
//2.閉包的執行就是花括號里面代碼的執行
//3.閉包接收的參數就是閉包參數closure參數中的i,如果是一個參數默認就是it變量
def mEach(closure){
for(int i in 1..5){
closure(i)
}
}
//向閉包傳遞參數
def mEachWithParams(closure){
def map = ["name":"Groovy","age":10]
map.each{
closure(it.key, it.value)
}
}
上面代碼中定義了閉包以及如何進行閉包的參數的傳遞,當閉包只有一個參數時,默認就是 it,反之閉包有多個參數時,就需要將參數定義出來,具體可參考上述代碼,下面是執行結果:
PS E:\Gradle\study\Groovy\Closure> gradle delegate
> Configure project :
1
2
3
4
5
name is Groovy
age is 10
BUILD SUCCESSFUL in 2s
閉包委托
Groovy 閉包的強大之處在於它支持閉包方法的委托,Groovy 的閉包有三個屬性:thisObject、owner、delegate,當在一個閉包中調用定義的方法時,由這三個屬性來確定該方法由哪個對象來執行,默認 owner 和 delegate 是相等的,其中 delete 是可以被修改的,Gradle 中閉包的很多功能都是通過修改 delegate 來實現的。下面通過定義一個閉包以及方法,通過打印來說明這三個屬性的一些區別:
//閉包的委托
task delegate{
new Delegate().test{
//Groovy閉包的三個屬性:thisObject、owner、delegate
println "thisObject:${thisObject.getClass()}"
println "owner:${owner.getClass()}"
println "delegate:${delegate.getClass()}"
//閉包默認it
println "閉包默認it:"+it.getClass()
//定義的方法,優先使用thisObject來處理
method()
//閉包中的方法
it.method()
}
}
def method(){
println "mththod in root:${this.getClass()}"
}
class Delegate{
def method(){
println "mththod in Delegate:${this.getClass()}"
}
//閉包
def test(Closure<Delegate> closure){
closure(this);
}
}
下面是上述代碼的執行結果,參考如下:
PS E:\Gradle\study\Groovy\Closure> gradle delegate
> Configure project :
thisObject:class build_3ajca04o1rprxygcsq0ajvt7i
owner:class build_3ajca04o1rprxygcsq0ajvt7i$_run_closure2
delegate:class build_3ajca04o1rprxygcsq0ajvt7i$_run_closure2
閉包默認it:class Delegate
mththod in root:class build_3ajca04o1rprxygcsq0ajvt7i
mththod in Delegate:class Delegate
BUILD SUCCESSFUL in 2s
當在閉包中調用方法 method() 時,發現是 thisObject 調用了 method() 方法,而不是 owner 或 delegate,說明閉包中優先使用 thisObject 來處理方法的執行,同時可以看到 owner 和 delegate 是一致的,但是 owner 比 delegate 的優先級要高,所以閉包中方法的處理順序是:thisObject > owner > delegate。
Gradle 中一般會指定 delegate 為當前的 it,這樣我們將可以通過 delegate 指定的對象來操作 it 了,下面指定閉包的 delegate 並設置委托優先,讓委托的具體對象來執行其方法,下面是測試代碼:
task student{
configStudent{
println "當前it:${it}"
name = "Groovy"
age = 10
getInfo()
}
}
class Student{
String name
int age
def getInfo(){
println "name is ${name}, age is ${age}"
}
}
def configStudent(Closure<Student> closure){
Student student = new Student()
//設置委托對象為當前創建的Student實例
closure.delegate = student
//設置委托模式優先,如果不設置閉包內方法的處理者是thisObject
closure.setResolveStrategy(Closure.DELEGATE_FIRST)
//設置it變量
closure(student)
}
下面是上述代碼的執行結果,參考如下:
PS E:\Gradle\study\Groovy\Closure> gradle student
> Configure project :
當前it:Student@18f6d755
name is Groovy, age is 10
BUILD SUCCESSFUL in 2s
總結
學習 Groovy 的目的還是為了加深對 Gradle 構建工具的理解,上面通過五個方面對 Groovy 有了初步的人認識,后續如果有需要在看 Groovy 的高級用法。
如果感興趣,可以關注公眾號:躬行之(jzman-blog),一起交流學習。