gradle學(xué)習(xí)-Groovy基礎(chǔ)

Groovy基礎(chǔ)

  • 字符串處理

每一門變成語言都會有字符串的處理,Java相對要稍微復(fù)雜一些,對程序員的開發(fā)限制比較多。相對而言,Groovy非常方便,比如字符串的運算、求值、正則等

在Groovy中分號不是必必需的。相信很多用Java的讀者都習(xí)慣了每一行結(jié)束必需要有分號,但是Groovy沒有這個強制規(guī)定。

1.單引號是單純的字符串常量
2.雙引號字符串常量里可以做許多運算操作,而單引號卻不能

task printString << {
   def str1 = '單引號'
   def str2 = "雙引號"
  println "單引號定義的字符串類型:"+str1.getClass().name
  println "雙引號定義的字符串類型:"+str2.getClass().name

  def name = "張三"
  println '單引號的變量計算:${name}'
  println "單引號的變量計算:${name}"
}

運算結(jié)果:

Task :printString
單引號定義的字符串類型:java.lang.String 雙引號定義的字符串類型:java.lang.String 單引號的變量計算:${name}
單引號的變量計算:張三

  • 集合
    在Java里,定義一個List,需要New一個實現(xiàn)了List接口的類,太繁瑣了。在Groovy中則非常簡單:
task printList << {
  def numList = [1, 2, 3, 4, 5, 6]
  println numList.getClass().name
}

Groovy提供下標(biāo)索引的方式訪問,就像數(shù)組一樣,除此之外,還提供了負(fù)下標(biāo)和范圍索引。負(fù)下標(biāo)索引代表從右邊開始,-1代表從右側(cè)第一個,-2代表從右側(cè)第二個,以此類推;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] = " + numList[1]//訪問第二個元素
  println "numList[-1] = " + numList[-1]//訪問最后一個元素
  println "numList[-2] = " + numList[-2]//訪問倒數(shù)第二個元素
  println "numList[1..3] = " + numList[1..3]//訪問第二個到第四個元素

  numList.each {
    print it
  }
}

it變量就是正在迭代的元素,這里有閉包的知識。我們可以先這么記住,后面會纖細(xì)講解。

  • Map

map的用法和List很像,只不過它的值是一個K:V鍵值對。所以在Groovy中Map的定義也非常簡單:

task printMap << {
  //Map的定義
  def map1 = ['width':1024,'height':768]
  println map1.getClass().name
  }

我們能看出Map的訪問也非常靈活,采用map[key]或者map.key的方式都可以,這兩種方式都能快速取出制定的key和value值,必用Java方便多了。
對于Map的迭代,當(dāng)然也少不了each方法,只不過被迭代的元素是一個Map.Entry的實例。

task printMap << {
  //Map的定義
  def map1 = ['width':1024,'height':768]
  println map1.getClass().name

  //map的訪問
  println map1['width']
  println map1.height

  //map的迭代
  map1.each {
    println "Key : Z ${it.key},Value:${it.value}"
  }

}

對于集合,Groovy還提供了許多諸如collect、find、findAll等便捷方法,有興趣的讀者可以找相關(guān)文檔看看,這里就不一一講了。

  • 方法

1. 括號是可以省略的
我們在Java中調(diào)用一個方法都是用invokeMethod(param1,param2),非常規(guī)范,Java就是這么中規(guī)中矩的語言。在Groovy中就要靈活得多,可以省略(),變成invokeMethod param1,param2這樣是不是覺得非常簡潔,這在DSL的時候非常有用,書寫也非常方便:

task invokeMethod << {
  method(1,2)
  method 1,2
}

def method(int a,int b){
  println a+b
}

task printMethodReturn << {
  def add1 = method2 1,2
  def add2 = method2 5,3
  println "add1:${add1},add2:${add2}"
}

2. return是可以不寫的
在Groovy中我們定義有返回值得方法時,return語句不是必需的。當(dāng)沒有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
  }
}

運行結(jié)果:

Task :printMethodReturn
add1:2,add2:5

3. 代碼塊是可以作為參數(shù)傳遞的
代碼塊是一段花括號包圍的代碼,其實就是后面要講的閉包。Groovy是允許其作為參數(shù)傳遞的,但是結(jié)合我們上面講的方法特性來用,最后的基于閉包的方法調(diào)用就會非常優(yōu)雅、易懂、以集合的each方法為例,它接受的參數(shù)其實就是一個閉包:

task myTask << {

  //呆板的寫法
  numList.each({ println it })

  //格式化以后,是不是更優(yōu)雅一些?
  numList.each({
    println it
  })

  //Groovy規(guī)定,如果方法的最后一個參數(shù)是閉包,可以放到方法外面
  numList.each(){
    println it
  }

  //然后方法可以省略,就變成我們經(jīng)??吹降臉邮?  numList.each {
    println it
  }

}
  • JavaBean

JavaBean是一個非常好的概念,你現(xiàn)在看到的組建化、插件化、配置集成都是基于JavaBean。在Java中為了訪問和修改JavaBean的屬性,我們不得不重復(fù)生成getter/setter方法,并且使用它們,太繁瑣,這在Groovy中得到很大的改善:

task helloJavaBean << {
   Person p = new Person()

  println "名字是: ${p.name}"
  p.name = '張三'
  println "名字是:${p.name}"
  println "age:${p.age}"

}

class Person {
  private String name
  public int getAge(){
     12
  }
}

Task :helloJavaBean
名字是: null
名字是:張三
age:12

在沒有給name屬性賦值的時候輸出null,賦值后輸出的就是“張三”了。通過上面的例子,我們發(fā)現(xiàn),在Groovy中可以非常容易地訪問和修改JavaBean的屬性值,而不用借助getter/setter方法,這是因為Groovy幫助我們搞定了一些功能。

  • 閉包

閉包是Groovy的一個非常重要的特性,可以說它是DSL的基礎(chǔ)。閉包不是Groovy的首創(chuàng),但是它支持這一重要的特性,這就是使得代碼靈活、輕量、可復(fù)用,再也不用像java一樣動不動就要用一個類了。雖然java后來有了匿名內(nèi)部類,但是一樣冗余不靈活。

1.初始閉包

task helloClosure << {
  //使用我們自定義的閉包
  MyEach {
    println it
  }
}


static def MyEach(closure){
  //模擬一個有10個元素的集合,開始迭代
  for(int i in 1..10){
    closure(i)
  }
}

在上面的例子中我們定義了一個方法MyEach,它只是一個參數(shù),用于接收一個閉包(代碼塊)。那么這個閉包如何執(zhí)行呢?很簡單,跟一對括號就是執(zhí)行了。

2.向閉包傳遞參數(shù)

當(dāng)閉包有一個參數(shù)時,默認(rèn)就是it;當(dāng)有多個參數(shù)時就不能這樣表示了,我們需要把參數(shù)一一列出

task helloParamsClosure << {
  eachMap {k,v ->
    println "${k} is ${v}"

  }

}

def eachMap(closure){
  def map1=["name":"張三","age":18]
  map1.each {
    closure(it.key,it.value)
  }
}

從這個例子中我們可以看出,我們?yōu)殚]包傳遞了兩個參數(shù),一個是key,一個是value。此時我們就不能使用it了,必須要顯式申明粗來,如例子中的k、v、-> 用于把閉包的參數(shù)和主體區(qū)分開來。

  • 委托閉包

Groovy閉包的強大之處在于它支持閉包方法的委托。Groovy的閉包有thisObject、owner、delegate三個屬性,當(dāng)你在閉包內(nèi)調(diào)用時,由他們確定使用哪個對象來處理。默認(rèn)情況下delegate和owner是相等的,但是delegate是可以被修改的,這個功能是非常強大的,Gradle中的閉包的很多功能都是通過修改delegate實現(xiàn)的:

task helloParamsClosure << {
  eachMap {k,v ->
    println "${k} is ${v}"

  }

}

def eachMap(closure){
  def map1=["name":"張三","age":18]
  map1.each {
    closure(it.key,it.value)
  }
}
task helloDelegate << {
  new Delegate().test {
    println "thisObject:${thisObject.getClass()}"
    println "owner:${owner.getClass()}"
    println "delegate:${delegate.getClass()}"
    method3()
    it.method3()
  }
}

def method3(){
  println "Context this:${this.getClass()} in root"
  println "method in root"
}

class Delegate {
  def method3(){
    println "Delegate this:${this.getClass()} in delegate"
    println "method in Delegate"
  }
  def test(Closure<Delegate> closure){
    closure(this)
  }
}

程序運行結(jié)果如下:

Task :helloDelegate
thisObject:class build_202knba1xpeza2oarchhbot3m
owner:class build_202knba1xpeza2oarchhbot3m_run_closure11 delegate:class build_202knba1xpeza2oarchhbot3m_run_closure11
Context this:class build_202knba1xpeza2oarchhbot3m in root
method in root
Delegate this:class Delegate in delegate
method in Delegate

通過上面的例子我們發(fā)現(xiàn),thisObject的優(yōu)先級最高,默認(rèn)情況下,優(yōu)先使用thisObject來處理閉包中調(diào)用的方法,如果有則先執(zhí)行。從輸出中我們可以看到,這個thisObject其實就是這個構(gòu)建腳本的上下文,它和腳本中的this對象是相等的。

從例子中也證明了delegate和owner是相等的,它們兩個的優(yōu)先級是:owner要比delegate高,所以閉包內(nèi)方法的處理順序是:thisObject>owner>delegate

在DSL中,比如Gradle,我們一般會指定delegate為當(dāng)前it,這樣我們在閉包內(nèi)就可以對it進(jìn)行配置,或者調(diào)用其方法:

task configClosure << {
  person {
    personName = "張三"
    personAge = 20
    dumpPerson()
  }
}

class Person {
  String personName
  int personAge
  def dumpPerson(){
    println "name is ${personName},age is ${personAge}"
  }
}

def person(Closure<Person> closure){
  Person p = new Person()
  closure.delegate = p
  closure.setResolveStrategy(Closure.DELEGATE_FIRST)
  closure(p)
}

運行結(jié)果如下:

Task :configClosure
name is 張三,age is 20

例子中我們設(shè)置了委托對象優(yōu)先,為當(dāng)前創(chuàng)建的Person實例,并且設(shè)置了委托模式,所以我們在使用person方法創(chuàng)建一個Person實例時,可以在閉包中直接對改Person實例進(jìn)行配置。有沒有發(fā)現(xiàn)和我們在Gradle中使用task創(chuàng)建一個Task的用法很像,其實在Gradle中有很多類似的用法,在Gradle中也基本都是使用delegate的方式使用閉包進(jìn)行配置等操作。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容