Gradle之Groovy語言的簡單認識(二)

筆記來源于:
https://blog.csdn.net/singwhatiwanna/article/details/76084580 http://liuwangshu.cn/application/gradle/3-groovy.html

1. Groovy簡介:

Groovy是一種基于JVM(Java虛擬機)的敏捷開發語言,它結合了Python、Ruby和Smalltalk的許多強大的特性,Groovy代碼能夠與Java代碼很好地結合,也能用于擴展現有代碼。由于其運行在 JVM 上的特性,Groovy 可以使用其他 Java 語言編寫的庫。

2. Groovy和Java的關系

Groovy是一種JVM語言,它最終是要變異成class文件然后在JVM上執行,所以Java語言的特性Groovy都支持,我們完全可以混寫Java和Groovy。

那么Groovy的優勢是什么呢?簡單來說,Groovy提供了更加靈活簡單的語法,大量的語法糖以及閉包特性可以讓你用更少的代碼來實現和Java同樣的功能。比如解析xml文件,Groovy就非常方便,只需要幾行代碼就能搞定,而如果用Java則需要幾十行代碼。

3. Groovy的變量和方法聲明

在Groovy中,通過def關鍵字來聲明變量和方法,比如:

class Demo1{
    def a=1;
    def b="hello world";
    def c=1;
    def hello(){
        println("hello world");
        return 1;
    }
}

在Groovy中,很多東西都是可以省略的,比如

  1. 語句后面的分號是可以省略的。
  2. 變量的類型和方法的返回值也是可以省略的。
  3. 方法調用時,括號也是可以省略的。
  4. 甚至語句中的return都是可以省略的。

上面的代碼也可以寫成如下形式

class Demo2 {
    def a = 1
    def b = "hello world"
    def int c = 1

    def hello() {
        println "hello world" //方法調用省略括號
        1;//方法返回值省略return
    }

    def hello(String msg) {
        println(msg)
    }
    //方法省略類型參數
    int hello(msg) {
        println(msg)
        return 1
    }
    //方法省略參數類型
    int hello1(msg) {
        println msg
        return 1//這個return不能省略
        println "done"
    }
}

總結:

  1. 在Groovy中,類型是弱化的,所有的類型都可以動態推斷,但是Groovy仍然是強類型的語言,類型不匹配仍然會報錯。
  2. 在Groovy中很多東西都可以省略,所以尋找一種自己喜歡的寫法。
  3. Groovy中的注釋和Java中相同。

4. Groovy的數據類型

在Groovy中,數據類型有:

  1. Java中的基本數據類型
  2. Java中的對象
  3. Closure(閉包)
  4. 加強的List、Map等集合類型
  5. 加強的File、Stream等IO類型

類型可以顯示聲明,也可以用def來聲明,用def聲明的類型Groovy將會進行類型推斷。

基本數據類型和對象在這里不用贅述,和Java中的一致,只不過在Gradle中,對象默認的修飾符為public。下面主要說下String、閉包、集合和IO等。

4.1. String

String的特色在于字符串的拼接,比如

class StringDemo {
    /**
     * 這里出現了字符串插值,除了單引號和三單引號字符串,所有的字符串都可以插入Groovy 表達式,三引號字符串可以保留文本的換行和縮進格式。
     * 插值實際就是替換字符串中的占位符,占位表達式是由${}包含起來或者是由$開頭的.表達式,
     * 當GString 被傳了一個帶有String參數的方法 時,通過調用toString()方法,可以把占位符里
     * 面的表達式解析為真正的值。
     * @return
     */
    def hello() {
        def a = 1
        def b = "hello"
        def c = "a=${a}, b=${b}"
        println(c)
    }
}


outputs:
a=1, b=hello
4.2. 閉包

Groovy中有一種特殊的類型,叫做Closure,翻譯過來就是閉包,這是一種類似于C語言中函數指針的東西。閉包用起來非常方便,在Groovy中,閉包作為一種特殊的數據類型而存在,閉包可以作為方法的參數和返回值,也可以作為一個變量而存在。

如何聲明閉包?

{ parameters -> 
   code
}

閉包可以有返回值和參數,當然也可以沒有。下面是幾個具體的例子:

def closure = { int a, String b ->
   println "a=${a}, b=${b}, I am a closure!"
}

// 這里省略了閉包的參數類型
def test = { a, b ->
   println "a=${a}, b=${b}, I am a closure!"
}

def ryg = { a, b ->
   a + b
}

closure(100, "renyugang")
test.call(100, 200)
def c = ryg(100,200)
println c

閉包可以當做函數一樣使用,在上面的例子中,將會得到如下輸出:

a=100, b=renyugang, I am a closure!
a=100, b=200, I am a closure!
300

另外,如果閉包不指定參數,那么他會有一個隱含的參數it

//這里省略了閉包的參數類型   
def test = {
    println "find ${it},I am a closure!"
}
test(100)

outputs:  
find 100,I am a closure!

閉包的一個難題是如何確定閉包的參數,尤其當我們調用Groovy的API時,這個時候沒有其他辦法,只有查詢Groovy的文檔:

http://www.groovy-lang.org/api.html

http://docs.groovy-lang.org/latest/html/groovy-jdk/index-all.html
下面會結合具體的例子來說明如何查文檔。

4.3 List和Map

Groovy加強了Java中的集合類,比如List、Map、Set等。

  • 1. List的使用如下
def emptyList = []

def test = [100, "hello", true]
test[1] = "world"
println test[0]
println test[1]
test << 200
println test.size

outputs:
100
world
4

List還有一種看起來很奇怪的操作符<<,其實這并沒有什么大不了,左移位表示向List中添加新元素的意思,這一點從文檔當也能查到。

You can access elements of the list with the [] subscript operator (both for reading and setting values) with positive indices or negative indices to access elements from the end of the list, as well as with ranges, and use the << leftShift operator to append elements to a list

def letters = ['a', 'b', 'c', 'd']

assert letters[0] == 'a'     //1
assert letters[1] == 'b'

assert letters[-1] == 'd'    //2
assert letters[-2] == 'c'

letters[2] = 'C'             //3
assert letters[2] == 'C'

letters << 'e'               //4
assert letters[ 4] == 'e'
assert letters[-1] == 'e'

assert letters[1, 3] == ['b', 'd']  //5         
assert letters[2..4] == ['C', 'd', 'e']   //6 
  1. Access the first element of the list (zero-based counting)
  2. Access the last element of the list with a negative index: -1 is the first element from the end of the list
  3. Use an assignment to set a new value for the third element of the list
  4. Use the << leftShift operator to append an element at the end of the list
  5. Access two elements at once, returning a new list containing those two elements
  6. Use a range to access a range of values from the list, from a start to an end element position

其實Map也有左移操作,這如果不查文檔,將會非常費解。

  • 2. Map使用如下:
def emptyMap = [:]
def test = ["id":1, "name":"renyugang", "isMale":true]
test["id"] = 2
test.id = 900
println test.id
println test.isMale

outputs:
900
true

可以看到,通過Groovy來操作List和Map顯然比Java簡單的多。

這里借助Map再講述下如何確定閉包的參數。比如我們想遍歷一個Map,我們想采用Groovy的方式,通過查看文檔,發現它有如下兩個方法,看起來和遍歷有關:

image

可以發現,這兩個each方法的參數都是一個閉包,那么我們如何知道閉包的參數呢?當然不能靠猜,還是要查文檔。

image

通過文檔可以發現,這個閉包的參數還是不確定的,如果我們傳遞的閉包是一個參數,那么它就把entry作為參數;如果我們傳遞的閉包是2個參數,那么它就把key和value作為參數。

按照這種提示,我們來嘗試遍歷下:

def emptyMap = [:]
def test = ["id":1, "name":"renyugang", "isMale":true]

test.each { key, value ->
   println "two parameters, find [${key} : ${value}]"
}

test.each {
   println "one parameters, find [${it.key} : ${it.value}]"
}

outputs:
two parameters, find [id : 1]
two parameters, find [name : renyugang]
two parameters, find [isMale : true]

one parameters, find [id : 1]
one parameters, find [name : renyugang]
one parameters, find [isMale : true]

這里貼出官方給的例子:

  1. 遍歷List:

    image

  2. 遍歷Map:

    image

4.4 加強的IO

在Groovy中,文件訪問要比Java簡單的多,不管是普通文件還是xml文件。怎么使用呢?還是來查文檔。

image

根據File的eachLine方法,我們可以寫出如下遍歷代碼,可以看到,eachLine方法也是支持1個或2個參數的,這兩個參數分別是什么意思,就需要我們學會讀文檔了,一味地從網上搜例子,多累啊,而且很難徹底掌握:

def file = new File("a.txt")
println "read file using two parameters"
file.eachLine { line, lineNo ->
   println "${lineNo} ${line}"
}

println "read file using one parameters"
file.eachLine { line ->
   println "${line}"
}

outputs:
read file using two parameters
1 hello
2 world
3 hello world

read file using one parameters
hello
world
hello world

除了eachLine,File還提供了很多Java所沒有的方法,大家需要瀏覽下大概有哪些方法,然后需要用的時候再去查就行了,這就是學習Groovy的正道。

下面我們再來看看訪問xml文件,也是比Java中簡單多了。
Groovy訪問xml有兩個類:XmlParser和XmlSlurper,二者幾乎一樣,在性能上有細微的差別,如果大家感興趣可以從文檔上去了解細節,不過這對于本文不重要。

在下面的鏈接中找到XmlParser的API文檔,參照例子即可編程

http://docs.groovy-lang.org/docs/latest/html/api/

假設我們有一個xml,attrs.xml,如下所示:

<resources>
<declare-styleable name="CircleView">

   <attr name="circle_color" format="color">#98ff02</attr>
   <attr name="circle_size" format="integer">100</attr>
   <attr name="circle_title" format="string">houyl</attr>
</declare-styleable>

</resources>

那么如何遍歷它呢?

def xml = new XmlParser().parse(new File("attrs.xml"))
// 訪問declare-styleable節點的name屬性
println xml['declare-styleable'].@name[0]

// 訪問declare-styleable的第三個子節點的內容
println xml['declare-styleable'].attr[2].text()


outputs:
CircleView
houyl

更多的細節都可以從我發的那個鏈接中查到,大家有需要查文檔即可。

5. for循環

Groovy支持Java的for(int i=0;i<N;i++)和for(int i :array)形式的循環語句,另外還支持for in loop形式,支持遍歷范圍、列表、Map、數組和字符串等多種類型。

//遍歷范圍
def x = 0
for ( i in 0..3 ) {
    x += i
}
assert x == 6
//遍歷列表
def 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

6. Groovy的其他特性

除了本文中已經分析的特性外,Groovy還有其他特性。

6.1 Class是一等公民

在Groovy中,所有的Class類型,都可以省略.class,比如:

func(File.class)
func(File)

def func(Class clazz) {
}
6.2 Getter和Setter

在Groovy中,Getter/Setter和屬性是默認關聯的,比如:

class Book {
   private String name
   String getName() { return name }
   void setName(String name) { this.name = name }
}

class Book {
   String name
}

上述兩個類完全一致,只有有屬性就有Getter/Setter;同理,只要有Getter/Setter,那么它就有隱含屬性。

6.3 with操作符

在Groovy中,當對同一個對象進行操作時,可以使用with,比如:

Book bk = new Book()
bk.id = 1
bk.name = "android art"
bk.press = "china press"

可以簡寫為:
Book bk = new Book() 
bk.with {
   id = 1
   name = "android art"
   press = "china press"
}


6.4 判斷是否為真可以更簡潔
if (name != null && name.length > 0) {}

可以替換為:
if (name) {}
6.5 簡潔的三元表達式

在Groovy中,三元表達式可以更加簡潔,比如:

def result = name != null ? name : "Unknown"

// 省略了name
def result = name ?: "Unknown"
6.6 簡潔的非空判斷

在Groovy中,非空判斷可以用?表達式,比如:

if (order != null) {
   if (order.getCustomer() != null) {
       if (order.getCustomer().getAddress() != null) {
       System.out.println(order.getCustomer().getAddress());
       }
   }
}

可以簡寫為:
println order?.customer?.address

6.7 使用斷言

在Groovy中,可以使用assert來設置斷言,當斷言的條件為false時,程序將會拋出異常:

def check(String name) {
   // name non-null and non-empty according to Groovy Truth
   assert name
   // safe navigation + Groovy Truth to check
   assert name?.size() > 3
}

6.8 switch方法

在Groovy中,switch方法變得更加靈活,可以同時支持更多的參數類型:

def x = 1.23
def result = ""
switch (x) {
   case "foo": result = "found foo"
   // lets fall through
   case "bar": result += "bar"
   case [4, 5, 6, 'inList']: result = "list"
   break
   case 12..30: result = "range"
   break
   case Integer: result = "integer"
   break
   case Number: result = "number"
   break
   case { it > 3 }: result = "number > 3"
   break
   default: result = "default"
}
assert result == "number"

6.9 ==和equal

在Groovy中,==相當于Java的equals,,如果需要比較兩個對象是否是同一個,需要使用.is()。

Object a = new Object()
Object b = a.clone()

assert a == b
assert !a.is(b)

7. 編譯、運行Groovy

配置好gradle的環境變量之后,然后就可以直接編譯運行Groovy寫的gradle文件了
在當面目錄下創建build.gradle文件,在里面創建一個task,然后在task中編寫Groovy代碼即可,如下所示:

task(houyl).doLast {
   println "start execute houyl"
   haveFun()
}

def haveFun() {
   println "have fun!"
   System.out.println("have fun!");
   1
   def file1 = new File("a.txt")
   def file2 = new File("a.txt")
   assert file1 == file2
   assert !file1.is(file2)
}

class Book {
   private String name
   String getName() { return name }
   void setName(String name) { this.name = name }
}

只需要在haveFun方法中編寫Groovy代碼即可,如下命令即可運行:

gradle houyl
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,963評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,348評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,083評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,706評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,442評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,802評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,795評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,983評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,542評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,287評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,486評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,030評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,710評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,116評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,412評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,224評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,462評論 2 378

推薦閱讀更多精彩內容

  • 前言 由于項目需要用到 Groovy 語言,這兩天對其進行了粗略的學習,本文是對學習做的一個簡單總結,主要內容參考...
    簡單的土豆閱讀 188,934評論 12 201
  • 最近在學習 Android 中 Gradle 相關的知識,如果想學好 Gradle,必要的 Groovy 基礎是不...
    lijiankun24閱讀 4,545評論 4 15
  • Groovy :是一種動態語言。 1:這種語言比較有特點,它和 Java 一樣,也運行于 Java 虛擬機中。簡單...
    PeytonWu閱讀 1,583評論 0 1
  • 在 Android Studio 構建的項目中,基于 Gradle 進行項目的構建,同時使用 Android DS...
    Ant_way閱讀 7,409評論 0 16
  • 中午出來發快遞,到了快遞站卻發現關門了,隔壁商鋪熱情的告訴我:工作人員回家吃午飯了,一會兒就回來。想想太陽這么毒,...
    玥靈兒閱讀 890評論 14 16