Android Gradle(三)Groovy快速入門指南
本文首發於微信公眾號「劉望舒」
原文連結: OA%3D%3D%26amp%3Bmid%3D2649842919%26amp%3Bidx%3D1%26amp%3Bsn%3D212eac39bf76c4340b165a558572ce7f%26amp%3Bchksm%3D83bf6dbcb4c8e4aaa82d57ad4667fbfa6c35102b0da5fd1d97f297fd33bbcd62be4e119c4eb7%26amp%3Bmpshare%3D1%26amp%3Bscene%3D1%26amp%3Bsrcid%3D1010Qs9OKGdv49VVZDIoWggv%26amp%3Bkey%3D3d5e46a9229dcee71a62f993ed7beed0784f93772df17d19ebe10901629adff1894a47f941384c078a0494c19512c9ef4faf5e25b3f8546825372eb812b4b21c5f12ce662bf9be54225be42a3cd73afc%26amp%3Bascene%3D1%26amp%3Buin%3DMTk4MjE1MDAyMA%253D%253D%26amp%3Bdevicetype%3DWindows-QQBrowser%26amp%3Bversion%3D6103000b%26amp%3Blang%3Dzh_CN%26amp%3Bpass_ticket%3DQzScu4H5XuZcEkOkgwaCpT%252Fd%252BV7VWpHbgVfWMpMZJCNAC4Ufap68mqrY1iYXW%252F1%252F" rel="nofollow,noindex">Groovy快速入門看這篇就夠了
前言
在前面我們學習了 為什麼現在要用Gradle? 和Gradle入門前奏兩篇文章,對Gradle也有了大概的瞭解,這篇文章我們接著來學習Groovy的基礎,要想學好Gradle,Groovy是必須要掌握的。Groovy僅憑一篇文章是介紹不完的,這裡會帶大家快速的入門Groovy,講解Groovy和Java不同的部分,想要更多瞭解Groovy可以檢視Groovy官方文件和 Groovy API文件 。
1.Groovy概述
Groovy是Apache 旗下的一種基於JVM的面向物件程式語言,既可以用於面向物件程式設計,也可以用作純粹的指令碼語言。在語言的設計上它吸納了Python、Ruby 和 Smalltalk 語言的優秀特性,比如動態型別轉換、閉包和超程式設計支援。 Groovy與 Java可以很好的互相呼叫並結合程式設計 ,比如在寫 Groovy 的時候忘記了語法可以直接按Java的語法繼續寫,也可以在 Java 中呼叫 Groovy 指令碼。比起Java,Groovy語法更加的靈活和簡潔,可以用更少的程式碼來實現Java實現的同樣功能。
2.Groovy編寫和除錯
Groovy的程式碼可以在Android+Studio/">Android Studio和IntelliJ IDEA等IDE中進行編寫和除錯,缺點是需要配置環境,這裡推薦在文字中編寫程式碼並結合命令列進行除錯(文字推薦使用Sublime Text)。關於命令列請檢視 Android Gradle(二)Gradle入門前奏 這篇文章。 具體的操作步驟就是:在一個目錄中新建build.gradle檔案,在build.gradle中新建一個task,在task中編寫Groovy程式碼,用命令列進入這個build.gradle檔案所在的目錄,執行gradle task名稱 等命令列對程式碼進行除錯,本文中的例子都是這樣編寫和除錯的。
3.變數
Groovy中用def關鍵字來定義變數,可以不指定變數的型別,預設訪問修飾符是public。
def a = 1; def int b = 1; def c = "hello world"; 複製程式碼
4.方法
方法使用返回型別或def關鍵字定義,方法可以接收任意數量的引數,這些引數可以不申明型別,如果不提供可見性修飾符,則該方法為public。 用def關鍵字定義方法。
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 } 複製程式碼
如果指定了方法返回型別,可以不需要def關鍵字來定義方法。
task method <<{ def number=minus 1,2 println number } int minus(a,b) { return a-b } 複製程式碼
如果不使用return ,方法的返回值為最後一行程式碼的執行結果。
int minus(a,b) { a-b //4 } 複製程式碼
從上面兩段程式碼中可以發現Groovy中有很多省略的地方:
- 語句後面的分號可以省略。
- 方法的括號可以省略,比如註釋1和註釋3處。
- 引數型別可以省略,比如註釋2處。
- return可以省略掉,比如註釋4處。
5.類
Groovy類非常類似於Java類。
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 } } 複製程式碼
執行 gradle method列印結果為: 15
Groovy類與Java類有以下的區別:
- 預設類的修飾符為public。
- 沒有可見性修飾符的欄位會自動生成對應的setter和getter方法。
- 類不需要與它的原始檔有相同的名稱,但還是建議採用相同的名稱。
6.語句
6.1 斷言
Groovy斷言和Java斷言不同,它一直處於開啟狀態,是進行單元測試的首選方式。
task method <<{ assert 1+2 == 6 } 複製程式碼
輸出結果為:
Execution failed for task ':method'. > assert 1+2 == 6 || 3false 複製程式碼
當斷言的條件為false時,程式會丟擲異常,不再執行下面的程式碼,從輸出可以很清晰的看到發生錯誤的地方。
6.2 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.3 switch語句
Groovy中的Switch語句不僅相容Java程式碼,還可以處理更多型別的case表示式。
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表示式可以是字串、列表、範圍、Integer等等,因為篇幅原因,這裡只列出了一小部分。
7. 資料型別
Groovy中的資料型別主要有以下幾種:
- Java中的基本資料型別
- Groovy中的容器類
- 閉包
7.1 字串
Groovy中的基本資料型別和Java大同小異,這裡主要介紹下字串型別。在Groovy種有兩種字串型別,普通字串String(java.lang.String)和插值字串GString(groovy.lang.GString)。
單引號字串在Groovy中單引號字串和雙引號字串都可以定義一個字串常量,只不過單引號字串不支援插值。
'Android進階解密' 複製程式碼
雙引號字串要想插值可以使用雙引號字串,插值指的是替換字串中的佔位符,佔位符表示式為 ${}
或者以 $
為字首。
def name = 'Android進階之光' println "hello ${name}" println "hello $name" 複製程式碼
三引號字串三引號字串可以保留文字的換行和縮排格式,不支援插值。
task method <<{ def name = '''Android進階之光 Android進階解密 Android進階?''' println name } 複製程式碼
列印結果為:
Android進階之光 Android進階解密 Android進階? 複製程式碼
GStringString是不可變的,GString卻是可變的,GString和String即使有相同的字面量,它們的hashCodes的值也可能不同,因此應該避免使用使用GString作為Map的key。
assert "one: ${1}".hashCode() != "one: 1".hashCode() 複製程式碼
當雙引號字串中包含插值表示式時,字串型別為GString,因此上面的斷言為true。
7.2 List
Groovy沒有定義自己的集合類,它在Java集合類的基礎上進行了增強和簡化。Groovy的List對應Java中的List介面,預設的實現類為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操作符來顯式指定List的實現類為java.util.LinkedList。 獲取元素同樣要比Java要簡潔些,使用 []
來獲取List中具有正索引或負索引的元素。
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是列表末尾的第一個元素。註釋2處使用 <<
運算子在列表末尾追加一個元素。
7.3 Map
建立Map同樣使用 []
,需要同時指定鍵和值,預設的實現類為java.util.LinkedHashMap。
def name = [one: '魏無羨', two: '楊影楓', three: '張無忌'] assert name['one']== '魏無羨' assert name.two== '楊影楓' 複製程式碼
Map還有一個鍵關聯的問題:
def key = 'name' def person = [key: '魏無羨'] //1 assert person.containsKey('key') person = [(key): '魏無羨'] //2 assert person.containsKey('name') 複製程式碼
註釋1處魏無羨的鍵值是key這個字串,而不是key變數的值 name。如果想要以key變數的值為鍵值,需要像註釋2處一樣使用(key),用來告訴解析器我們傳遞的是一個變數,而不是定義一個字串鍵值。
7.4 閉包(Closure)
Groovy中的閉包是一個開放的、匿名的、可以接受引數和返回值的程式碼塊。 定義閉包 閉包的定義遵循以下語法:
{ [closureParameters -> ] statements } 複製程式碼
閉包分為兩個部分,分別是引數列表部分 [closureParameters -> ]
和語句部分 statements 。 引數列表部分是可選的,如果閉包只有一個引數,引數名是可選的,Groovy會隱式指定it作為引數名,如下所示。
{ println it }//使用隱式引數it的閉包 複製程式碼
當需要指定引數列表時,需要 ->
將引數列表和閉包體相分離。
{ it -> println it }//it是一個顯示引數 { String a, String b -> println "${a} is a ${b}" } 複製程式碼
閉包是groovy.lang.Cloush類的一個例項,這使得閉包可以賦值給變數或欄位,如下所示。
//將閉包賦值給一個變數 def println ={ it -> println it } assert println instanceof Closure //將閉包賦值給Closure型別變數 Closure do= { println 'do!' } 複製程式碼
呼叫閉包閉包既可以當做方法來呼叫,也可以顯示呼叫call方法。
def code = { 123 } assert code() == 123 //閉包當做方法呼叫 assert code.call() == 123 //顯示呼叫call方法 def isOddNumber = { int i -> i%2 != 0 } assert isOddNumber(3) == true//呼叫帶引數的閉包 複製程式碼
8. I/O 操作
Groovy的 I/O 操作要比Java的更為的簡潔。
8.1 檔案讀取
我們可以在PC上新建一個name.txt,在裡面輸入一些內容,然後用Groovy來讀取該檔案的內容:
def filePath = "D:/Android/name.txt" def file = new File(filePath) ; file.eachLine { println it } 複製程式碼
可以看出Groovy的檔案讀取是很簡潔的,還可以更簡潔些:
def filePath = "D:/Android/name.txt" def file = new File(filePath) ; println file.text 複製程式碼
8.2 檔案寫入
檔案寫入同樣十分簡潔:
def filePath = "D:/Android/name.txt" def file = new File(filePath); file.withPrintWriter { it.println("三井壽") it.println("仙道彰") } 複製程式碼
9. 其他
9.1 asType
asType可以用於資料型別轉換:
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中,要安全獲取某個物件的值可能需要大量的if語句來判空:
if (school != null) { if (school.getStudent() != null) { if (school.getStudent().getName() != null) { System.out.println(school.getStudent().getName()); } } } 複製程式碼
Groovy中可以使用 ?.
來安全的取值:
println school?.student?.name 複製程式碼
9.4 with操作符
對同一個物件的屬性進行賦值時,可以這麼做:
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來進行簡化:
Person p = new Person() p.with { name = "楊影楓" age= 19 sex= "男" } println p.name 複製程式碼
10.總結
本文大概的介紹了Groovy的一些語法,包括:變數、方法、資料型別等等,比起Groovy 官方文件來說,介紹的並不多,但不要忘了本系列的目標是學習與Android相關的Gradle,Groovy並不是重點,我們只需要瞭解本文所介紹的內容就夠了,如果碰到哪裡不會再去查詢Groovy 官方文件和Groovy API文件。
分享Android、Java和大前端相關技術
