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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章