Markdown版本筆記 | 個人GitHub首頁 | 個人博客 | 個人微信 | 個人郵箱 |
---|---|---|---|---|
MyAndroidBlogs | baiqiantao | baiqiantao | bqt20094 | baiqiantao@sina.com |
Gradle Groovy 基礎語法 MDhtml
Gradle是目前Android主流的構建工具,無論你是經過命令行仍是經過AndroidStudio來build,最終都是經過Gradle來實現的。因此學習Gradle很是重要。git
目前國內對Android領域的探索已經愈來愈深,很多技術領域如插件化、熱修復、構建系統
等都對Gradle有迫切的需求,不懂Gradle將沒法完成上述事情。因此Gradle必需要學習。github
Gradle不僅僅是一個配置腳本,它的背後是幾門語言:api
DSL的全稱是
Domain Specific Language
,即領域特定語言,或者直接翻譯成「特定領域的語言」,再直接點,其實就是這個語言不通用,只能用於特定的某個領域,俗稱「小語言」。所以DSL也是語言。微信
實際上,Gradle腳本大多都是使用groovy語言編寫的。閉包
Groovy是一門jvm語言,功能比較強大,細節也不少,所有學習的話比較耗時,對咱們來講收益較小,而且玩轉Gradle並不須要學習Groovy的所有細節,因此其實咱們只須要學一些Groovy基礎語法與API便可。app
Groovy是一種基於JVM的敏捷開發語言,它結合了衆多腳本語言的強大的特性,因爲同時又能與Java代碼很好的結合。一句話:既有面向對象的特性又有純粹的腳本語言的特性。jvm
因爲Groovy運行在JVM上,所以也可使用Java語言編寫的組建。ide
簡單來講,Groovy提供了更加靈活簡單的語法
,大量的語法糖
以及閉包
特性可讓你用更少的代碼來實現和Java一樣的功能
。
Groovy是一門jvm語言,它最終是要編譯成class文件而後在jvm上執行,因此Java語言的特性Groovy都支持
,Groovy支持99%的java語法,咱們徹底能夠在Groovy代碼中直接粘貼java代碼。
能夠安裝Groovy sdk
來編譯和運行。可是我並不想搞那麼麻煩,畢竟咱們的最終目的只是學習Gradle。
推薦你們經過這種方式來編譯和運行Groovy。
在當面目錄下建立build.gradle
文件,在裏面建立一個task
,而後在task中編寫Groovy代碼便可,以下所示:
task(testGroovy).doLast { println "開始運行自定義task" test() } def test() { println "執行Groovy語法的代碼" System.out.println("執行Java語法的代碼!"); }
而後在命令行終端中執行以下命令便可:
gradle testGroovy
> Configure project :app > Task :app:testGroovy 開始運行自定義task 執行Groovy語法的代碼 執行Java語法的代碼! BUILD SUCCESSFUL in 3s 1 actionable task: 1 executed
咱們知道,在Android項目中,咱們只要更改build.gradle
文件一點內容,AS就會提示咱們同步:
可是在咱們測試 Groovy 時中,咱們更改build.gradle
文件後能夠沒必要去同步,執行命令時會自動執行你修改後的最新邏輯。
Groovy中的類和方法默認都是public權限的,因此咱們能夠省略public關鍵字,除非咱們想使用private。
Groovy中的類型是弱化的,全部的類型均可以動態推斷
,可是Groovy仍然是強類型的語言
,類型不匹配仍然會報錯。
Groovy中經過 def
關鍵字來聲明變量和方法
。
Groovy中不少東西都是能夠省略的,好比
省略return關鍵字並非一個好的習慣,就如同 if else while 後面只有一行語句時能夠省略大括號同樣,之後若是添加了其餘語句,頗有可能會致使邏輯錯誤
def int a = 1; //若是 def 和 類型同時存在,IDE 會提示你"def是不須要的(is unnecessary)" def String b = "hello world" //省略分號,存在分號時也會提示你 unnecessary def c = 1 //省略類型 def hello() { //省略方法聲明中的返回值類型 println ("hello world"); println "hello groovy" //省略方法調用時的圓括號 return 1; } def hello(String msg) { println "hello" + msg //省略方法調用時的圓括號 1; //省略return } int hello(msg) { //省略方法聲明中的參數類型 println msg return 1 // 這個return不能省略 println "done" //這一行代碼是執行不到的,IDE 會提示你 Unreachable statement,但語法沒錯 }
在Groovy中,數據類型有:
Closure(閉包)
類型能夠顯示聲明,也能夠用 def 來聲明,用 def 聲明的類型Groovy將會進行類型推斷。
基本數據類型和對象和Java中的一致,只不過在Gradle中,對象默認的修飾符爲public
。
String的特點在於字符串的拼接,好比
def a = 1 def b = "hello" def c = "a=${a}, b=${b}" println c //a=1, b=hello
Groovy中有一種特殊的類型,叫作Closure
,翻譯過來就是閉包,這是一種相似於C語言中函數指針
的東西。
閉包用起來很是方便,在Groovy中,閉包做爲一種特殊的數據類型
而存在,閉包能夠做爲方法的參數和返回值,也能夠做爲一個變量而存在
。
閉包能夠有返回值和參數
,固然也能夠沒有。下面是幾個具體的例子:
def test() { def closure = { String parameters -> //閉包的基本格式 println parameters } def closure2 = { a, b -> // 省略了閉包的參數類型 println "a=${a}, b=${b}" } def closure3 = { a -> a + 1 //省略了return } def closure4 = { // 省略了閉包的參數聲明 println "參數爲 ${it}" //若是閉包不指定參數,那麼它會有一個隱含的參數 it } closure("包青天") //包青天 closure2 10086, "包青天" //a=10086, b=包青天 println closure3(1) //2 //println closure3 2 //不容許省略圓括號,會提示:Cannot get property '1' on null object closure4() //參數爲 null closure4 //不容許省略圓括號,可是並不會報錯 closure4 10086 //參數爲 10086 }
閉包的一個難題是如何肯定閉包的參數(包括參數的個數、參數的類型、參數的意義),尤爲當咱們調用Groovy的API時,這個時候沒有其餘辦法,只有查詢Groovy的文檔才能知道。
Groovy增強了Java中的集合類,好比List、Map、Set等。
基本使用以下:
def emptyList = [] def list = [10086, "hello", true] list[1] = "world" assert list[1] == "world" println list[0] //10086 list << 5 //至關於 add() assert 5 in list // 調用包含方法 println list //[10086, world, true, 5]
def range = 1..5 assert 2 in range println range //1..5 println range.size() //5
def emptyMap = [:] def map = ["id": 1, "name": "包青天"] map << [age: 29] //添加元素 map["id"] = 10086 //訪問元素方式一 map.name = "哈哈" //訪問元素方式二,這種方式最簡單 println map //{id=10086, name=哈哈, age=29}
能夠看到,經過Groovy來操做List和Map顯然比Java簡單的多。
上面有一個看起來很奇怪的操做符<<
,其實這並無什麼大不了,<<
表示向List中添加新元素
的意思,這一點從 List文檔 當也能查到。
public List leftShift(Object value)
左移位運算符
,以提供將對象append
到List的簡單方法。實際上,這個運算符是大量使用的,而且當你用 leftShift
方法時 IDE 也會提示你讓你使用左移位
運算符<<
替換:
def list = [1, 2] list.leftShift 3 assert list == [1, 2, 3] list << 4 println list //[1, 2, 3, 4]
這裏藉助Map再講述下如何肯定閉包的參數。好比咱們想遍歷一個Map,咱們想採用Groovy的方式,經過查看文檔,發現它有以下兩個方法,看起來和遍歷有關:
Map each(Closure closure)
:Allows a Map to be iterated through using a closure.Map eachWithIndex(Closure closure)
:Allows a Map to be iterated through using a closure.能夠發現,這兩個each方法的參數都是一個閉包,那麼咱們如何知道閉包的參數呢?固然不能靠猜,仍是要查文檔。
public Map each(Closure closure)
one parameter
then it will be passed the Map.Entry
otherwise if the closure takes two parameters
then it will be passed the key and the value
.TreeMap
will have its contents processed according to the natural ordering(天然順序) of the map.def result = "" [a:1, b:3].each { key, value -> result += "$key$value" } //兩個參數 assert result == "a1b3"
def result = "" [a:1, b:3].each { entry -> result += entry } //一個參數 assert result == "a=1b=3" [a: 1, b: 3].each { println "[${it.key} : ${it.value}]" } //一個隱含的參數 it,key 和 value 是屬性名
試想一下,若是你不知道查文檔,你又怎麼知道each方法如何使用呢?光靠從網上搜,API文檔中那麼多接口,搜的過來嗎?記得住嗎?
在Groovy中,文件訪問要比Java簡單的多,不論是普通文件仍是xml文件。怎麼使用呢?查來 File文檔。
public Object eachLine(Closure closure)
能夠看到,eachLine方法也是支持1個或2個參數的,這兩個參數分別是什麼意思,就須要咱們學會讀文檔了,一味地從網上搜例子,多累啊,並且很難完全掌握:
def file = new File("a.txt") file.eachLine { line, lineNo -> println "${lineNo} ${line}" //行號,內容 } file.eachLine { line -> println "${line}" //內容 }
除了eachLine,File還提供了不少Java所沒有的方法,你們須要瀏覽下大概有哪些方法,而後須要用的時候再去查就好了,這就是學習Groovy的正道。
Groovy訪問xml有兩個類:XmlParser
和XmlSlurper
,兩者幾乎同樣,在性能上有細微的差異,不過這對於本文不重要。
groovy.util.XmlParser
的 API文檔
文檔中的案例:
def xml = '<root><one a1="uno!"/><two>Some text!</two></root>' //或者 def xml = new XmlParser().parse(new File("filePath.xml")) def rootNode = new XmlParser().parseText(xml) //根節點 assert rootNode.name() == 'root' //根節點的名稱 assert rootNode.one[0].@a1 == 'uno!' //根節點中的子節點 one 的 a1 屬性的值 assert rootNode.two.text() == 'Some text!' //根節點中的子節點 two 的內容 rootNode.children().each { assert it.name() in ['one','two'] }
更多的細節查文檔便可。
當你在Groovy中建立一個beans的時候,一般咱們稱爲POGOS(Plain Old Groovy Objects),Groovy會自動幫咱們建立getter/setter
方法。
當你對getter/setter
方法有特殊要求,你儘可提供本身的方法,Groovy默認的getter/setter
方法會被替換。
有一個bean
class Server { String name Cluster cluster }
初始化一個實例的時候你可能會這樣寫:
def server = new Server() server.name = "Obelix" server.cluster = aCluster
其實你能夠用帶命名的參數的默認構造器,會大大減小代碼量:
def server = new Server(name: "Obelix", cluster: aCluster)
在Groovy中Class類型的.class
後綴不是必須的,好比:
def func(Class clazz) { println clazz } func(File.class) //class java.io.File func(File) //class java.io.File
當更新一個實例的時候,你可使用with()來省略相同的前綴,好比:
Book book = new Book() book.with { id = 1 //等價於 book.id = 1 name = "包青天" start(10086) stop("包青天") }
全部類型都能轉成布爾值,好比null
和void
至關於0
或者至關於false
,其餘則至關於true
,因此:
if (name) {} //等價於 if (name != null && name.length > 0) {}
在Groovy中能夠在類中添加asBoolean()
方法來自定義是否爲真
。
在Groovy中,三元表達式能夠更加簡潔,好比:
def result = name ?: "" //等價於 def result = name != null ? name : ""
若是你實在不想關心try
塊裏拋出何種異常,你能夠簡單的捕獲全部異常,而且能夠省略異常類型:
try { // ... } catch (any) { //能夠省略異常類型 // something bad happens }
這裏的any並不包括Throwable
,若是你真想捕獲everything,你必須明確的標明你想捕獲Throwable
在java中,你要獲取某個對象的值必需要檢查是否爲null,這就形成了大量的if
語句;在Groovy中,非空判斷能夠用?.
表達式,好比:
println order?.customer?.address //等價於 if (order != null) { if (order.getCustomer() != null) { if (order.getCustomer().getAddress() != null) { System.out.println(order.getCustomer().getAddress()); } } }
在Groovy中,可使用assert來設置斷言,當斷言的條件爲false時,程序將會拋出異常
:
def check(String name) { assert name // 檢查方法傳入的參數是否爲空,name non-null and non-empty according to Groovy Truth assert name?.size() > 3 }
Groovy裏的is()
方法等同於Java裏的==
。
Groovy中的==
是更智能的equals()
,比較兩個類的時候,你應該使用a.is(b)
而不是==
。
Groovy中的==
能夠自動避免NullPointerException異常
status == "包青天" //等價於Java中的 status != null && status.equals("包青天")
在Groovy中,switch方法變得更加靈活,能夠同時支持更多的參數類型:
def x = null def result = "" switch (x) { case "foo": result = "found foo" //沒有 break 時會繼續向下判斷 case "bar": result += "bar" break case [4, 5, 6]: result = "list" //匹配集合中的元素 break case 12..30: result = "range" //匹配某個範圍內的元素 break case Integer: result = "integer" //匹配Integer類型 break case { it > 3 }: result = "number > 3" //匹配表達式 break case Number: result = "number" //匹配Number類型 break default: result = "default" } println result
Java中,字符串過長鬚要換行時咱們通常會這樣寫:
throw new PluginException("Failed to execute command list-applications:" + " The group with name " + parameterMap.groupname[0] + " is not compatible group of type " + SERVER_TYPE_NAME)
Groovy中你能夠用 \
字符,而不須要添加一堆的雙引號:
throw new PluginException("Failed to execute command list-applications: \ The group with name ${parameterMap.groupname[0]} \ is not compatible group of type ${SERVER_TYPE_NAME}")
或者使用多行字符串"""
:
throw new PluginException("""Failed to execute command list-applications: The group with name ${parameterMap.groupname[0]} is not compatible group of type ${SERVER_TYPE_NAME)}""")
Groovy中,單引號
引發來的字符串是java字符串,不能使用佔位符來替換變量,雙引號
引發的字符串則是java字符串或者Groovy字符串。
在java中使用兩個類名相同但包名不一樣的兩個類,像java.util.List
和java.wt.List
,你必須使用完整的包名才能區分。Groovy中則可使用import別名:
import java.util.List as jurist //使用別名 import java.awt.List as aList import java.awt.WindowConstants as WC import static pkg.SomeClass.foo //靜態引入方法
2019-1-12