Gradle核心思想(三)Groovy快速入門(mén)指南

本文首發(fā)于 公眾號(hào) 劉望舒
關(guān)聯(lián)系列
Android Gradle系列

前言

在前面我們學(xué)習(xí)了為什么現(xiàn)在要用Gradle?Gradle入門(mén)前奏兩篇文章,對(duì)Gradle也有了大概的了解,這篇文章我們接著來(lái)學(xué)習(xí)Groovy的基礎(chǔ),要想學(xué)好Gradle,Groovy是必須要掌握的。Groovy僅憑一篇文章是介紹不完的,這里會(huì)帶大家快速的入門(mén)Groovy,講解Groovy和Java不同的部分,想要更多了解Groovy可以查看Groovy官方文檔Groovy API文檔

1.Groovy概述

Groovy是Apache 旗下的一種基于JVM的面向?qū)ο缶幊陶Z(yǔ)言,既可以用于面向?qū)ο缶幊?,也可以用作純粹的腳本語(yǔ)言。在語(yǔ)言的設(shè)計(jì)上它吸納了Python、Ruby 和 Smalltalk 語(yǔ)言的優(yōu)秀特性,比如動(dòng)態(tài)類(lèi)型轉(zhuǎn)換、閉包和元編程支持。
Groovy與 Java可以很好的互相調(diào)用并結(jié)合編程 ,比如在寫(xiě) Groovy 的時(shí)候忘記了語(yǔ)法可以直接按Java的語(yǔ)法繼續(xù)寫(xiě),也可以在 Java 中調(diào)用 Groovy 腳本。比起Java,Groovy語(yǔ)法更加的靈活和簡(jiǎn)潔,可以用更少的代碼來(lái)實(shí)現(xiàn)Java實(shí)現(xiàn)的同樣功能。

2.Groovy編寫(xiě)和調(diào)試

Groovy的代碼可以在Android Studio和IntelliJ IDEA等IDE中進(jìn)行編寫(xiě)和調(diào)試,缺點(diǎn)是需要配置環(huán)境,這里推薦在文本中編寫(xiě)代碼并結(jié)合命令行進(jìn)行調(diào)試(文本推薦使用Sublime Text)。關(guān)于命令行請(qǐng)查看Android Gradle(二)Gradle入門(mén)前奏這篇文章。
具體的操作步驟就是:在一個(gè)目錄中新建build.gradle文件,在build.gradle中新建一個(gè)task,在task中編寫(xiě)Groovy代碼,用命令行進(jìn)入這個(gè)build.gradle文件所在的目錄,運(yùn)行g(shù)radle task名稱(chēng) 等命令行對(duì)代碼進(jìn)行調(diào)試,本文中的例子都是這樣編寫(xiě)和調(diào)試的。

3.變量

Groovy中用def關(guān)鍵字來(lái)定義變量,可以不指定變量的類(lèi)型,默認(rèn)訪問(wèn)修飾符是public。

def a = 1;
def int b = 1;
def c = "hello world";

4.方法

方法使用返回類(lèi)型或def關(guān)鍵字定義,方法可以接收任意數(shù)量的參數(shù),這些參數(shù)可以不申明類(lèi)型,如果不提供可見(jiàn)性修飾符,則該方法為public。
用def關(guān)鍵字定義方法。

task method <<{
    add (1,2)
    minus 1,2 //1
}
def add(int a,int b) { 
 println a+b //3
}  
def minus(a,b) {//2 
 println a-b
}   

如果指定了方法返回類(lèi)型,可以不需要def關(guān)鍵字來(lái)定義方法。

task method <<{
    def number=minus 1,2
    println number
}
int minus(a,b) { 
  return a-b 
}  

如果不使用return ,方法的返回值為最后一行代碼的執(zhí)行結(jié)果。

int minus(a,b) { 
  a-b //4
}  

從上面兩段代碼中可以發(fā)現(xiàn)Groovy中有很多省略的地方:

  1. 語(yǔ)句后面的分號(hào)可以省略。
  2. 方法的括號(hào)可以省略,比如注釋1和注釋3處。
  3. 參數(shù)類(lèi)型可以省略,比如注釋2處。
  4. return可以省略掉,比如注釋4處。

5.類(lèi)

Groovy類(lèi)非常類(lèi)似于Java類(lèi)。

task method <<{
    def p = new Person()
    p.increaseAge 5
    println p.age
}
class Person {                       
    String name                      
    Integer age =10
    def increaseAge(Integer years) { 
        this.age += years
    }
}

運(yùn)行 gradle method打印結(jié)果為:
15

Groovy類(lèi)與Java類(lèi)有以下的區(qū)別:

  1. 默認(rèn)類(lèi)的修飾符為public。
  2. 沒(méi)有可見(jiàn)性修飾符的字段會(huì)自動(dòng)生成對(duì)應(yīng)的setter和getter方法。
  3. 類(lèi)不需要與它的源文件有相同的名稱(chēng),但還是建議采用相同的名稱(chēng)。

6.語(yǔ)句

6.1 斷言

Groovy斷言和Java斷言不同,它一直處于開(kāi)啟狀態(tài),是進(jìn)行單元測(cè)試的首選方式。

task method <<{
  assert 1+2 == 6
}

輸出結(jié)果為:

Execution failed for task ':method'.
> assert 1+2 == 6
          |  |
          3  false

當(dāng)斷言的條件為false時(shí),程序會(huì)拋出異常,不再執(zhí)行下面的代碼,從輸出可以很清晰的看到發(fā)生錯(cuò)誤的地方。

6.2 for循環(huán)

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

//遍歷范圍
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.3 switch語(yǔ)句

Groovy中的Switch語(yǔ)句不僅兼容Java代碼,還可以處理更多類(lèi)型的case表達(dá)式。

task method <<{
def x = 16
def result = ""

switch ( x ) {
    case "ok":
        result = "found ok"
    case [1, 2, 4, 'list']:
        result = "list"
        break
    case 10..19:
        result = "range"
        break
    case Integer:
        result = "integer"
        break
    default:
        result = "default"
}
assert result == "range"
}

case表達(dá)式可以是字符串、列表、范圍、Integer等等,因?yàn)槠?,這里只列出了一小部分。

7. 數(shù)據(jù)類(lèi)型

Groovy中的數(shù)據(jù)類(lèi)型主要有以下幾種:

  • Java中的基本數(shù)據(jù)類(lèi)型
  • Groovy中的容器類(lèi)
  • 閉包

7.1 字符串

Groovy中的基本數(shù)據(jù)類(lèi)型和Java大同小異,這里主要介紹下字符串類(lèi)型。在Groovy種有兩種字符串類(lèi)型,普通字符串String(java.lang.String)和插值字符串GString(groovy.lang.GString)。

單引號(hào)字符串
在Groovy中單引號(hào)字符串和雙引號(hào)字符串都可以定義一個(gè)字符串常量,只不過(guò)單引號(hào)字符串不支持插值。

'Android進(jìn)階解密'

雙引號(hào)字符串
要想插值可以使用雙引號(hào)字符串,插值指的是替換字符串中的占位符,占位符表達(dá)式為${}或者以$為前綴。

def name = 'Android進(jìn)階之光'
println "hello ${name}"
println "hello $name"

三引號(hào)字符串
三引號(hào)字符串可以保留文本的換行和縮進(jìn)格式,不支持插值。

task method <<{
def name = '''Android進(jìn)階之光
       Android進(jìn)階解密
Android進(jìn)階?'''
println name 
}

打印結(jié)果為:

Android進(jìn)階之光
       Android進(jìn)階解密
Android進(jìn)階?

GString
String是不可變的,GString卻是可變的,GString和String即使有相同的字面量,它們的hashCodes的值也可能不同,因此應(yīng)該避免使用使用GString作為Map的key。

assert "one: ${1}".hashCode() != "one: 1".hashCode()

當(dāng)雙引號(hào)字符串中包含插值表達(dá)式時(shí),字符串類(lèi)型為GString,因此上面的斷言為true。

7.2 List

Groovy沒(méi)有定義自己的集合類(lèi),它在Java集合類(lèi)的基礎(chǔ)上進(jìn)行了增強(qiáng)和簡(jiǎn)化。Groovy的List對(duì)應(yīng)Java中的List接口,默認(rèn)的實(shí)現(xiàn)類(lèi)為Java中的ArrayList。

def number = [1, 2, 3]         
assert number instanceof List  
def linkedList = [1, 2, 3] as LinkedList    
assert linkedList instanceof java.util.LinkedList

可以使用as操作符來(lái)顯式指定List的實(shí)現(xiàn)類(lèi)為java.util.LinkedList。
獲取元素同樣要比Java要簡(jiǎn)潔些,使用[]來(lái)獲取List中具有正索引或負(fù)索引的元素。

task method <<{
def number  = [1, 2, 3, 4]   
assert number [1] == 2
assert number [-1] == 4 //1  

number << 5     //2             
assert number [4] == 5
assert number [-1] == 5
}

注釋1處的索引-1是列表末尾的第一個(gè)元素。注釋2處使用<<運(yùn)算符在列表末尾追加一個(gè)元素。

7.3 Map

創(chuàng)建Map同樣使用[],需要同時(shí)指定鍵和值,默認(rèn)的實(shí)現(xiàn)類(lèi)為java.util.LinkedHashMap。

def name = [one: '魏無(wú)羨', two: '楊影楓', three: '張無(wú)忌']   
assert name['one']  == '魏無(wú)羨' 
assert name.two  == '楊影楓'

Map還有一個(gè)鍵關(guān)聯(lián)的問(wèn)題:

def key = 'name'
def person = [key: '魏無(wú)羨'] //1
assert person.containsKey('key') 
person = [(key): '魏無(wú)羨'] //2       
assert person.containsKey('name') 

注釋1處魏無(wú)羨的鍵值是key這個(gè)字符串,而不是key變量的值 name。如果想要以key變量的值為鍵值,需要像注釋2處一樣使用(key),用來(lái)告訴解析器我們傳遞的是一個(gè)變量,而不是定義一個(gè)字符串鍵值。

7.4 閉包(Closure)

Groovy中的閉包是一個(gè)開(kāi)放的、匿名的、可以接受參數(shù)和返回值的代碼塊。
定義閉包
閉包的定義遵循以下語(yǔ)法:

{ [closureParameters -> ] statements }

閉包分為兩個(gè)部分,分別是參數(shù)列表部分[closureParameters -> ]和語(yǔ)句部分 statements 。
參數(shù)列表部分是可選的,如果閉包只有一個(gè)參數(shù),參數(shù)名是可選的,Groovy會(huì)隱式指定it作為參數(shù)名,如下所示。

{ println it }     //使用隱式參數(shù)it的閉包                                 

當(dāng)需要指定參數(shù)列表時(shí),需要->將參數(shù)列表和閉包體相分離。

{ it -> println it }   //it是一個(gè)顯示參數(shù) 
{ String a, String b ->                                
    println "${a} is a $"
}   

閉包是groovy.lang.Cloush類(lèi)的一個(gè)實(shí)例,這使得閉包可以賦值給變量或字段,如下所示。

//將閉包賦值給一個(gè)變量
def println ={ it -> println it }     
assert println instanceof Closure
//將閉包賦值給Closure類(lèi)型變量
Closure do= { println 'do!' }                      

調(diào)用閉包
閉包既可以當(dāng)做方法來(lái)調(diào)用,也可以顯示調(diào)用call方法。

def code = { 123 }
assert code() == 123 //閉包當(dāng)做方法調(diào)用
assert code.call() == 123 //顯示調(diào)用call方法
def isOddNumber = { int i -> i%2 != 0 }                           
assert isOddNumber(3) == true  //調(diào)用帶參數(shù)的閉包

8. I/O 操作

Groovy的 I/O 操作要比Java的更為的簡(jiǎn)潔。

8.1 文件讀取

我們可以在PC上新建一個(gè)name.txt,在里面輸入一些內(nèi)容,然后用Groovy來(lái)讀取該文件的內(nèi)容:

def filePath = "D:/Android/name.txt"
def file = new File(filePath) ;
file.eachLine {
    println it
}

可以看出Groovy的文件讀取是很簡(jiǎn)潔的,還可以更簡(jiǎn)潔些:

def filePath = "D:/Android/name.txt"
def file = new File(filePath) ;
println file.text

8.2 文件寫(xiě)入

文件寫(xiě)入同樣十分簡(jiǎn)潔:

def filePath = "D:/Android/name.txt"
def file = new File(filePath);

file.withPrintWriter {
    it.println("三井壽")
    it.println("仙道彰")
}

9. 其他

9.1 asType

asType可以用于數(shù)據(jù)類(lèi)型轉(zhuǎn)換:

String a = '23'
int b = a as int
def c = a.asType(Integer)
assert c instanceof java.lang.Integer

9.2 判斷是否為真

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

可以替換為

if (name) {}

9.3 安全取值

在Java中,要安全獲取某個(gè)對(duì)象的值可能需要大量的if語(yǔ)句來(lái)判空:

if (school != null) {
    if (school.getStudent() != null) {
        if (school.getStudent().getName() != null) {
            System.out.println(school.getStudent().getName());
        }
    }
}

Groovy中可以使用?.來(lái)安全的取值:

println school?.student?.name

9.4 with操作符

對(duì)同一個(gè)對(duì)象的屬性進(jìn)行賦值時(shí),可以這么做:

task method <<{
Person p = new Person()
p.name = "楊影楓"
p.age = 19
p.sex = "男"
println p.name
}
class Person {                       
    String name                      
    Integer age
    String sex
}

使用with來(lái)進(jìn)行簡(jiǎn)化:

Person p = new Person()
p.with {
   name = "楊影楓"
   age= 19
   sex= "男"
 }   
println p.name

10.總結(jié)

本文大概的介紹了Groovy的一些語(yǔ)法,包括:變量、方法、數(shù)據(jù)類(lèi)型等等,比起Groovy 官方文檔來(lái)說(shuō),介紹的并不多,但不要忘了本系列的目標(biāo)是學(xué)習(xí)與Android相關(guān)的Gradle,Groovy并不是重點(diǎn),我們只需要了解本文所介紹的內(nèi)容就夠了,如果碰到哪里不會(huì)再去查找Groovy 官方文檔和Groovy API文檔。

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

相關(guān)閱讀更多精彩內(nèi)容

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