Gradle(1)- Groovy基礎 一.開發環境準備 二. 開發實戰 10. 文件IO 11. 解析XML 12.其他

Gradle是目前Android主流的構建工具,不管你是通過命令行還是通過Android Studio來build,最終都是通過Gradle來實現的,所以學習Gradle非常重要。

Groovy最終被編譯成class字節碼文件運行在jvm上,所以Java的特性Groovy都支持,但是Groovy提供了一些更加簡潔的語法,比如利用閉包特性來進行文件IO,解析XML,簡直讓你難以置信。

一.開發環境準備

  • 方式一:安裝Groovy SDK,安裝方法參考 http://www.groovy-lang.org/download.html,下載後解壓即可,最好是設置一下環境變量。
  • 方式二:直接在Android Studio中開發,創建一個普通的Android Project,在build.gradle文件中編寫一個task來執行,示例:
task(jdqm).doLast {
    println "Start execute hello."
    hello()
}

def hello() {
    println "Hello jdqm."
    //todo add your code here
}

在hello方法中編寫你的Groovy代碼,然後通過如下命令來執行

gradlew jdqm

作爲Android開發者,個人比較推薦是用第二種方式,畢竟我們的目標是Gradle。

二. 開發實戰

Groovy中的註釋與Java中的一樣,單行註釋//,多行註釋/**/

1.def關鍵字定義變量

def int aInt = 1;
def String aString = "I am a String.";
  • 分號不是必須的
  • def關鍵字可省略
  • 數據類型自動推斷

上面的代碼可以寫成這樣

aInt = 1
aString = "I am a String."
bInt = 2

2.方法的參數類型和返回值類型可省略

def getSomeThing(param1) {
    return param1
}
println getSomeThing("Hello Jdqm.")

請注意 println getSomeThing("Hello Jdqm.") 這一行,實際是調用了 println(String)這個方法,但你會發現沒有圓括號,所以方法調用圓括號也不是是必須的,前提是不引起混淆。下面這兩種寫法效果是一樣的:

println getSomeThing("Hello Jdqm.")
println(getSomeThing("Hello Jdqm."))

那什麼時候會混淆,比如

//方法調用省略圓括號,容易引起混淆,getSomeThing 會被當成屬性
println getSomeThing "Hello Jdqm."

3.return關鍵字可省略

//return關鍵字可省略,返回值爲最後一條語句的執行結果
def getSomeThings(param1, param2) {
    param1 + param2
}

result = getSomeThings 3, 4
println result // 7

注意:方法的返回值類型和def關鍵字不能同時省略,否則會報找不到方法。

4.字符串

//單引號爲嚴格意義的字符串,輸出 I am $ dollar
String singleQuote(){
    return 'I am $ dollar'
}
println singleQuote() // I am $ dollar
//雙引號不是嚴格的字符串,如果其中有$表達式,會先對錶達式求值
String doubleQuote(){
    def x = 1
    "I am $x dollar" 
}
println doubleQuote()  // I am 1 dollar
//三引號可以隨意換行
String threeQuote(){
    '''line1
    line2
    line3'''
}  

5.自動類型推斷

//自動推斷類型
def x = 1
println x.getClass().getCanonicalName() //java.lang.Integer

6.加強版 List

List可以存放任何類型的數據類型

List emptyList = []  // 通過[]來創建List
List testList=[100, 'hello', true]
println(testList[0])  //100
println(testList[1])  //hello
println(testList[2])  // true
assert testList[0]==100  //true
assert testList[100]==null / /true
//不會有下標越界異常,自動擴展List的大小
testList[100]=10
println testList[100]  //10
println testList.size()  //101,注意這個List的大小已經變爲101,那麼中間的元素默認值是什麼是什麼?是null

是不是特別像Java中的List<Object>

7.Map

通過[:]來創建,key默認是String,可以不加引號,但是容易引起混淆,單引號雙引號都可以。

Map emptyMap = [:]
Map testMap = ['key1':'value1','key2':'value2']
println(testMap.key1)  //value1
println(testMap['key2']) //傳統的取值方式
testMap.anotherkey='anothervalue' //添加一個元素
println testMap.anotherkey  //anothervalue

8.Range

def aRange=1..5    //1 2 3 4 5
def bRange=1..<5    //1 2 3 4
println aRange.from    //1
println aRange.to    //5
println bRange.from    //1
println bRange.to    //4

其中 aRange.from這種調用方式,實際上是調用了aRange.getFrom()方法。

9.閉包

閉包是一個比較重要的內容。

def aClosure = {String param1, String param2->
    println param1
    println param2
}

//有兩種調用方式
aClosure.call('hello', 'groovy')
aClosure('hello','groovy')

定義無參數closure,不代表不能傳參數

def bClosure={
   println 'hello world of groovy.'
   println it  // 沒有定義參數的時候,有一個隱含參數it
}
bClosure.call()    //不傳參數調用,it爲null
bClosure(100)    //it爲100

下面這種寫法表示閉包沒有參數,調用時不能傳入參數,否則會報錯

def cClosure={->
    println 'hello world.'
}

//不傳入參數調用,正確
cClosure.call()

//這樣調用會報錯
//cClosure.call('test')

方法的最後一個參數是閉包,可以將這個閉包參數寫到圓括號外

def testClosure(int a, String param, Closure closure){
    println ("$a,$param")
    closure.call()
}

//傳統的調用方式
testClosure(10, 'groovy',{
    println('I am a Closure')
})

//最後一個參數寫到圓括號外
testClosure(10, 'groovy') {
   println('I am a Closure')
}

10. 文件IO

首先回顧一下在Java中進行文件IO,假設存在這樣的test.txt

hello
groovy
I
am 
Jdqm.

現在需要通過Java IO讀這個文件的內容並輸出到控制檯

BufferedReader bufferedReader = null;
try {
    File file = new File("test.txt");

    //文本內容可以使用字符流
    FileReader fileReader = new FileReader(file);
    
    //將字符流包裝爲BufferReader,方便按行讀取
    bufferedReader = new BufferedReader(fileReader);
    String line;
    while ((line = bufferedReader.readLine()) != null) {
        System.out.println(line);
    }
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (bufferedReader != null) {
        try {
            bufferedReader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

即便使用Java7中的自動關閉流來省略掉finally塊,代碼仍然比較繁瑣。接下來使用Groovy來完成同樣的功能。

File file = new File('test.txt')
file.eachLine {online->
    println online
}

到這裏我只想到兩個詞:簡潔、明瞭。這裏使用到了閉包,而閉包的難點是如何確定參數,最好的方式是查官方文檔。http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/File.html#eachLine(groovy.lang.Closure)

從文檔說明中我們得知調用時閉包可以是1個或者2個參數, 第一個參數是當前行的內容,第二個參數(可選)是當前的行號(從1開始)。所以我們可以這樣

File file = new File('test.txt')
file.eachLine{line, lineNum ->
    println lineNum + " " + line
}

//輸出結果
1 hello
2 groovy
3 I
4 am
5 Jdqm.

下面將test.txt的內容寫入test1.txt

File sourceFile = new File('test.txt')
File targetFile = new File('test1.txt')
targetFile.withOutputStream{os->
    sourceFile.withInputStream{is->
        os<<is
    }
}

11. 解析XML

Groovy訪問xml有兩個類:XmlParser和XmlSlurper,二者幾乎一樣,在性能上有細微的差別,參考鏈接 http://docs.groovy-lang.org/docs/latest/html/api/

    def xml = '<root><one a1="uno!"/><two>Some text!</two></root>'
    def rootNode = new XmlParser().parseText(xml)
    assert rootNode.name() == 'root'
    assert rootNode.one[0].@a1 == 'uno!'
    assert rootNode.two.text() == 'Some text!'
    rootNode.children().each { assert it.name() in ['one','two'] }

12.其他

在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,那麼它就有隱含屬性。

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"
}

判斷是否爲真
在Groovy中,判斷是否爲真可以更簡潔:

if (name != null && name.length > 0) {}

可以替換爲:

if (name) {}

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

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

// 省略了name
def result = name ?: "Unknown"

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

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

可以簡寫爲:

println order?.customer?.address

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

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

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"

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

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

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

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