Gradle學習筆記之Groovy


Gradle是一個基於Apache Ant和Apache Maven概念的項目自動化構建工具。它使用一種基於Groovy的特定領域語言(DSL)來聲明項目設置,拋棄了基於XML的各種繁瑣配置。Gradle的構建腳本build.gradle和setting.gradle都是可執行的Groovy腳本(不過它們不可以在Groovy運行時環境下運行, 由於上述.gradle文件都需要調用gradle的api運行且后綴不是.groovy). 下面通過與Java對比, 簡單介紹小於Gradle相關的Groovy語言知識.

1. 什么是Groovy

Groovy是一個基於Java虛擬機的動態語言。這門動態語言擁有類似Python、Ruby和Smalltalk中的一些特性,可以作為Java平台的腳本語言使用。Groovy的語法與Java非常相似,以至於多數的Java代碼也是正確的Groovy代碼.

  1. Java開發者提供了 現代最流行的編程語言特性,而且學習成本很低。
  2. 支持DSL(Domain Specific Languages領域定義語言)和其它簡潔的語法,讓你的代碼變得易於閱讀和維護.
  3. 無縫集成所有已經存在的 Java對象和類庫.
  4. 接編譯成Java字節碼,這樣可以在任何使用Java的地方 使用Groovy。

2. Java VS Groovy

下面先給出Groovy運行環境下含義相同的Java和Groovy
代碼片, 然后在說明二者的區別

java

public class Me {
    private String name; 
    public Me(String name) { this.name = name; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

groovy

class Me {
    String name
    public Me(String name) { this.name = name}
}

從上面我們可以看到Groovy版本更加簡潔,下面給出Groovy相對於Java的特點:

  1. 表達式后面的分號;是可選的;
  2. 每個, 構造器, 方法訪問屬性默認是public的
  3. 方法體中的最后一個表達式的值被作為返回值, 這意味着return語句是可選的;
  4. Groovy編譯器自動加上getter/setter方法, 不需要自己手動添加;
  5. 類的屬性可以通過點號.獲取與賦值, 底層是通過調用自動生成的getter/setter方法.
  6. Groovy中用==比較兩個實例, 底層調用的是equals()方法, 這個操作也可以避免可能的空指針異常.

3. Groovy 高級特性

3.1 可選類型定義

作為動態語言,groovy中所有的變量都是對象,在聲明一個變量時,groovy不要求強制類型聲明,僅僅要求變量名前使用關鍵字def, def關鍵字作為java.lang.Object的一個占位符, 在運行時確定類型.

//assert用於斷言檢查 )
def var = 1
assert var.class == java.lang.Integer
var = "bupt"
assert var.class == java.lang.String

3.2 可選的括號

在Groovy中如果方法簽名需要至少一個參數, 則方法調用可以省略括號.


def callMe(name) {
    new Me(name)
}

callMe('faith')
callMe 'faith'

println("we could not live without faith!")
println "we could not live without faith!"

3.3 字符串

在Groovy中, 有三種不同方式定義字符串. 帶單引號'的通常創建等效於Java的String類型; 第二種和Java相同用雙引號"包起來, 跨行的字符串用三個雙引號包起來""".

幾點說明:

  1. 跟java一樣,可以使用+號連接字符串;
  2. Groovy中帶雙引號的字符串可以插值帶變量或者表達式中, 通過$和花括號{}表示, 運行時, Groovy計算表達式並組成字符串.這種字符串在Groovy中叫做GString. 通過下面的例子s4 s5也能看到和單引號的不同.
def s1 = 'bupt'
def s2 = "bupt"
def s3 = """b
u
p
t
"""
def s4 = "hello "+
"${s1}"
def s5 = "hello "+
'${s1}'
println s1
println s2
println s3
println s4

輸出:

bupt
bupt
b
u
p
t
hello bupt
hello ${s1}

3.4 命名參數

Groovy 中提供了一個減少輸入的特性叫做命名參數(Named Parameter)。GroovyBean 可以通過在構造器調用中傳遞冒號隔開的屬性名稱和值進行構建。如:

class Me {
    String name
}

Me me = new Me(name: "faith")
println me.name
me.name = 'bupt'
println me.name

輸出:
faith
bupt

從外部表現上好像是先調用了空構造方法,然后是相應的 setter 方法進行設值。因此,我們所直接想像的應該相當於下列 Java 代碼:

Me me = new Me();
me.setName("faith");

3.5 閉包

在介紹閉包前,先來講幾個Groovy中代碼塊的一些特性。

3.5.1 代碼塊

  1. groovy的變量作用域和java相似,代碼塊內部聲明的變量不能被外部訪問調用。
  2. 對於Groovy Script, 用def定義的變量對binding.variables不可見。沒有def等任何定義的可被binding.variable.參數名所訪問。
  3. 對於第一條規則,有個例外,當變量沒有def等任何定義時,該變量全局有效.
  4. 代碼塊可以嵌套,比如try代碼塊,這和Java是一樣的。
try{
  h = 9
  assert binding.variables.h == 9
}
assert h == 9
assert binding.variables.h == 9

3.5.2 閉包簡介

閉包是類型為groovy.lang.Closure用花括號{}括起來的代碼塊. 類似於Python的lambda表達式, 閉包可以被賦值給變量, 作為參數傳遞給方法, 並且像普通方法一樣調用.

看起來,閉包類似於方法,需要定義參數和要執行的語句,它也可以通過名稱被調用。然而閉包對象可以作為參數傳遞. 其次,閉包也可以不命名(當然作為代價,只能在定義閉包時執行一次)

3.5.3 閉包參數

1.顯示參數閉包:

閉包的參數聲明寫在‘->’符號前,調用閉包的的標准寫法是:閉包名.call(閉包參數)。

def toTriple = {n -> n * 3}
assert toTriple.call( 5 ) == 15

2.隱士參數閉包:

對於單一存在的參數it可以不用聲明,直接使用it,it在Groovy中有着特殊的意義;當且僅當閉包中有且僅有一個參數,且不顯示聲明,it具有唯一參數引用的作用;如果閉包c是無參數閉包,那么它的標准調用方法是c.call(),它的簡潔調用方法是c()。

c = { it*3 }
assert c( 'run' ) == 'runrunrun'
  
def a = 'coffee'
def c = {
  def b = 'tea'
  a + ' and ' + b 
  }
assert c() == 'coffee and tea' 

3.閉包隱含參數

參數 說明
it 默認的參數名,調用是如果沒有傳參數,it為null
this 跟Java一樣,是定義閉包所在類的一個引用,不管有多少層閉包嵌套,this指向的都是最上層的類。
owner 封閉閉包的對象(如果只有一層閉包就是this,如果有多層閉包嵌套就是含有此閉包的上層閉包)
delegate 缺省值是owner,但是可以改變,后面詳說。

4.閉包中的參數名不能重復,it除外。

def name= 'cup'
def c={ name-> println (name) } 
//a compile error when uncommented:
//current scope already contains name 'name'
c= { def d= { 2 * it }; 3 * d(it) }
assert c(5) == 30

5.閉包是可嵌套的

def gcd //predefine closure name
gcd={ m,n-> m%n==0? n: gcd(n,m%n) }
assert gcd( 28, 35 ) == 7

3.5.4 閉包返回值

閉包總是會有一個返回值,返回值是閉包的最后一行語句,不論該語句是否冠名return關鍵字。如果閉包最后一句沒有值, 返回 null;

3.5.5 賦值與調用

賦值: 閉包賦值給一個變量,和變量與變量間的賦值一致。

def c
try{
 def a = 'sugar'
 c = { a } //a closure always returns its only value
}
assert c() == 'sugar'
def d = c //we can also assign the closure to another variable
assert d() == 'sugar'

調用: 調用閉包的方法等於創建一個閉包實例。對於相同閉包創建出來的不同實例,他們的對象是不同的。

c = { def e = { 'milk' }; e }
d = c
assert c == d
v1 = c()
v2 = c()
assert v1 != v2

3.5.6 閉包委托

delegate委托的用法
delegate委托在是一種常用設計模式,但在java中實現相對比較繁瑣,groovy直接在GroovyObject中已經實現了delegate模式,所以在groovy中應用delegate很方便。

下面看一個狗爸爸讓老貓幫忙照看他的狗兒子玩游戲的例子:

class Dog{
    def play = {
      "wang wang!"
    }
    def childmind = {
        println       delegate.play();      
    }
}

class Cat {
    def play = {"mi mi !"}
}

def dog = new Dog()
def cat = new Cat()

dog.childmind()

dog.childmind.delegate  = cat;
dog.childmind()


3.6 集合

Groovy支持最常見的兩個java集合:
java.util.Collection和java.util.Map。

3.6.1 Collection

//1、定義一個集合
def collect = ["a","b","c"]

//2、給集合增加元素
collect.add(1);
collect << "come on";
collect[collect.size()] = 100.0

//3、集合索引
println collect[collect.size()-1]
println collect
println collect.size()

//4、負索引
println collect[-1]      //索引其倒數第1個元素
println collect[-2]      //索引其倒數第2個元素

//5、集合運算:
collect=collect+5        //在集合中添加元素5
println collect[collect.size()-1]

collect=collect-'a'         //在集合中減去元素a(第1個)
println collect[0]          //現在第1個元素變成b了

//6、往集合中添加另一個集合或刪除一個集合:
collect=collect-collect[0..4]   //把集合中的前5個元素去掉
println collect[0]   //現在集合中僅有一個元素,即原來的最后一個元素
println collect[-1]  //也可以用負索引,證明最后一個元素就是第一個元素

3.6.2 Map

Map是“鍵-值”對的集合,在groovy中,鍵不一定是String,可以是任何對象(實際上Groovy中的Map就是java.util.LinkedHashMap)。

//1、定義一個Map:
def map = ['name':'john','age':14,'sex':'boy']
println map

//2、添加項:
map = map+['weight':25]       //添加john的體重
map.put('length',1.27)      //添加john的身高
map.father='Keller'         //添加john的父親
println map

//3、兩種方式檢索值:
println map['father']       //通過key作為下標索引
println map.length          //通過key作為成員名索引

閉包中最常見的應用是對集合進行迭代,下面定義了3個閉包對map進行了迭代:

def map = ['name':'john','age':14,'sex':'boy']
map.each(
        {key,value->     // key,value兩個參數用於接受每個元素的鍵/值
    println "$key:$value"})

map.each{println it}     //it是一個關鍵字,代表map集合的每個元素
map.each({ println it.getKey()+"-->"+it.getValue()})

打印如下:

name:john
age:14
sex:boy
name=john
age=14
sex=boy
name-->john
age-->14
sex-->boy




參考:

  1. Groovy基礎——Closure(閉包)詳解
  2. Unmi 學習 Groovy 之命名參數
  3. Groovy語言學習:groovy語言簡介及基本語法
  4. <gradle實戰>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM