Android Gradle指南--2.Groovy基礎

  • Groovy是基於jvm虛擬機的一種動態腳本語言,徹底兼容java,又在此基礎上增長了不少動態類型和靈活的特性
  1. groovy 命令相似於 Java 中的 java 命令,用於執行 groovy Class 字節碼文件;
  2. groovyc 命令相似於 Java 中的 javac 命令,用於將 groovy 源文件編譯成 groovy 字節碼文件;
  3. groovysh 命令是用來解釋執行 groovy 腳本文件;
  • 下面是 Groovy 中全部的關鍵字,命名時尤爲須要注意:
as、assert、breakcase、catch、class、const、continue、def、default、doelse、enum、extends、false、finally、for、goto、if、implements、import、in、instanceof、interface、new、null、package、return、super、switch、this、throw、throws、trait、true、try、while
複製代碼
  • groovy中句末的分號不是必須的,函數調用的時候還能夠不加括號。

若是當前這個函數是 Groovy API 或者 Gradle API 中比較經常使用的,好比 println,就能夠不帶括號。不然仍是帶括號。否則,Groovy 可能會把屬性和函數調用混淆。java

  • 在 Groovy 中,== 至關於 Java 的 equals,,若是須要比較兩個對象是不是同一個,須要使用 .is()
  • Groovy 中函數的返回值也能夠是無類型的,而且無返回類型的函數,其內部都是按返回 Object 類型來處理的
  • 全部的 Class 類型,均可以省略 .class
  • 非運算符: assert (!"android") == false
  • 支持 ** 次方運算符: assert 2 ** 3 == 8
  • 判斷是否爲真: if (android) {}
  • 三元表達式: def result = name ?: "Unknown"
  • 非空判斷: println order?.customer?.address
  • 使用 assert 來設置斷言,當斷言的條件爲 false 時,程序將會拋出異常
  • 使用 Number 類去替代 float、double 等類型,省去考慮精度的麻煩
  • switch 方法能夠同時支持更多的參數類型
// 輸出 ok
def num = 5.21
switch (num) {
   case [5.21, 4, "list"]:
       return "ok"
       break
   default:
       break
}
複製代碼

變量

  • 變量類型 Groovy 中的類型同 Java 同樣,也是分爲兩種:基本類型,對象類型。

可是,其實 Groovy 中並無基本類型,Groovy 做爲動態語言, 在它的世界中,全部事物都是對象,就如 Python、Kotlin 同樣:全部的基本類型都是屬於對象類型。android

  • 變量的定義有兩種方式
  1. 強類型定義方式:即像 Java 同樣,在聲明變量的時候定義它的類型。
  2. 弱類型定義方式:經過 def關鍵字來定義咱們任何的變量,由於編譯器會根據值的類型來爲它進行自動的賦值。

若是這個變量就是用於當前類或文件,而不會用於其它類或應用模塊,那麼,建議使用 def 類型,由於在這種場景下弱類型就足夠了。 可是,若是你這個類或變量要用於其它模塊的,建議不要使用 def,仍是應該使用 Java 中的那種強類型定義方式,由於使用強類型的定義方式,它不能動態轉換爲其它類型,它可以保證外界傳遞進來的值必定是正確的。編程

字符串

  • 單雙引號均可以定義一個字符串常量,但單引號不能對字符串常量裏的表達式作運算
task groovyString{
	doLast{
		def name="abc"
		println '單引號的變量計算:${name}'
		println "雙引號的變量計算:${name}"
		println "$name" //只有一個變量時可省略大括號
		println "${1+2*3}"
	}
}

gradle groovyString

> Task :groovyString
單引號的變量計算:${name}
雙引號的變量計算:abc
abc
7
複製代碼

Groovy 中還新增了一個 GString 類型(當雙引號種包含表達式運算時,打印其類型就是GString),編譯器能夠幫咱們自動在 String 和 GString 之間相互轉換,咱們在編寫的時候並不須要太過關注它們的區別。bash

集合

  • List,Set,Map,Queue
task printList {
	def numList=[10,11,12,13,14]
	println numList.getClass().name
	println numList[0]
	println numList[1]
	println numList[-1]
	println numList[1..3]
	
	numList.each{
		println it
	}
}

$ gradle printList

> Configure project :
java.util.ArrayList
10
11
14
[11, 12, 13]
10
11
12
13
14

task printMap{
	def map1=['width':1080,'height':1920]
	println map1.getClass().name
	println map1['width']
	println map1.height
	map1.each{
		println "key=${it.key}, value=${it.value}"
	}

}

$ gradle printMap

> Configure project :
java.util.LinkedHashMap
1080
1920
key=width, value=1080
key=height, value=1920

複製代碼

方法

  • 括號能夠省略,如println 'abc'
  • return能夠省略,把最後一句看成返回值
task printMethodReturn{
	def add1=method1 1,2
	def add2=method1 6,4
	println "add1=$add1,add2=$add2"
}

def method1(int a,int b){
	if(a>b)
		a
	else
		b
}


$ gradle printMethodReturn

> Configure project :
add1=2,add2=6

複製代碼
  • 代碼塊能夠做爲參數傳遞
task printEach{
	def list=[11,12,13,14]
	//下面幾種打印it寫法
	list.each({println it})
	list.each({
		println it
	})
	//方法的最後一個參數是閉包能夠放到方法外面
	list.each(){
		println it
	}
	//方法能夠省略括號
	list.each{
		println it
	}
}

複製代碼

Groovy 面向對象

若是不聲明 public/private 等訪問權限的話,Groovy 中類及其變量默認都是 public 的;閉包

JavaBean
  • 可省略setter/getter方法,經過setter/getter也能夠代替成員變量的聲明
task printJavaBean{
	Person p=new Person()
	println "name=$p.name"
	p.name="bob"
	println "name=$p.name"
	println "age=$p.age"
	
}

class Person{
	private String name
	public int getAge(){
		28
	}
}

gradle printJavaBean

> Configure project :
name=null
name=bob
age=28

複製代碼
元編程(Groovy 運行時)
腳本中的變量和做用域

對於每個 Groovy 腳原本說,它都會生成一個 static void main 函數,main 函數中會調用一個 run 函數,腳本中的全部代碼則包含在 run 函數之中app

當咱們在 Groovy 腳本中定義一個變量時,因爲它其實是在 run 函數中建立的,因此腳本中的其它方法或其餘腳本是沒法訪問它的。這個時候,咱們須要使用 @Field 將當前變量標記爲成員變量jvm

import groovy.transform.Field; 
    
@Field author = JinYang
複製代碼

閉包

相似lambda表達式函數

task helloClosure{
	customEach{
		println it
	}

	eachMap {k,v ->
		println "$k is $v"
	}
}

def customEach(closure){
	for(int i in 1..10){
		closure(i)
	}
}

//向閉包傳參數
def eachMap(closure){
	def map=['name':'zhangsan','age':18]
	map.each{
		closure(it.key,it.value)
	}
}


複製代碼

groovy支持閉包方法的委託,其閉包有三個屬性thisObject,owner,delegate, 調用閉包方法時,由他們肯定使用哪一個對象來處理gradle

task helloDelegate{
	new Delegate().test{
		println "thisObject:${thisObject.getClass()}"
		println "owner:${owner.getClass()}"
		println "delegate:${delegate.getClass()}"
		method1()
		it.method1()
	}
}

def method1(){
	println "Context this:${this.getClass()} int root"
	println "method1 in root"
}

class Delegate{
	def method1(){
		println "Delegate this:${this.getClass()} in Delegate"
		println "method1 in Delegate"
	}

	def test(Closure<Delegate> closure){
		closure(this)
	}

}

$ gradle helloDelegate

thisObject:class build_d0vx8g4wj498jzsd4g4xes7j2
owner:class build_d0vx8g4wj498jzsd4g4xes7j2$_run_closure11
delegate:class build_d0vx8g4wj498jzsd4g4xes7j2$_run_closure11
Context this:class build_d0vx8g4wj498jzsd4g4xes7j2 int root
method1 in root
Delegate this:class Delegate in Delegate
method1 in Delegate


複製代碼

DSL中,好比Gradle,咱們通常指定delegate爲當前的it,這樣咱們在閉包內就能夠對該it進行配置,或調用其方法ui

task configClosure{
	dog{
		dogName="bob"
		dogAge=7
		dumpDog()
	}
}

class Dog{
	String dogName
	int dogAge

	def dumpDog(){
		println "name is $dogName,age is $dogAge"
	}
}

def dog(Closure<Dog> closure){
	Dog d=new Dog()
	closure.delegate=d
	//委託模式優先
	closure.setResolveStrategy(Closure.DELEGATE_FIRST)
	closure(d)
}

複製代碼

DSL

領域特定語言,在專而不在全,如Gradle是基於groovy,專門解決自動化構建的DSL

文件處理

讀取文件
  • eachLine
task readLine{
	def file =new File("./info.txt")
	file.eachLine{ String oneLine ->
		println oneLine
	}
	def text=file.getText()
	println text
	def text2=file.readLines()
	println text2
	file.eachLine{oneLine,lineNo ->
		println "${lineNo} --> ${oneLine}"
	}
}

$ gradle readLine -b file.gradle

> Configure project :
zhangsan
lisi
wangwu
zhaoliu
zhangsan
lisi
wangwu
zhaoliu
[zhangsan, lisi, wangwu, zhaoliu]
1 --> zhangsan
2 --> lisi
3 --> wangwu
4 --> zhaoliu
複製代碼
  • InputStream 也能夠經過流的方式進行文件操做
//操做 ism,最後記得關掉
def ism = targetFile.newInputStream() 
// do sth
ism.close

//利用閉包來操做 inputStream,其功能更增強大,推薦使用這種寫法
targetFile.withInputStream{ ism ->
    // 操做 ism,不用 close。Groovy 會自動替你 close 
}
複製代碼
寫入文件
  • 經過 withOutputStream/、withInputStream copy 文件
task writeFile{
	def srcFile=new File('./info.txt')
	def targetFile=new File('./copyInfo.txt')
	targetFile.withOutputStream{ os->
		srcFile.withInputStream{ ins->
			//利用 OutputStream 的<<操做符重載,完成從 inputstream 到 OutputStream //的輸出
			os << ins
		}
	}
}
複製代碼
  • 經過 withReader、withWriter copy 文件
task writeFile2{
	try{
		def srcFile=new File('./info.txt')
		def targetFile=new File('./copyInfo.txt')
		
		if(!targetFile.exists()){
			targetFile.createNewFile()
		}

		srcFile.withReader{reader ->
			def lines = reader.readLines()
			targetFile.withWriter{writer ->
				lines.each{line ->
					writer.append(line + "\r\n")
				}
			}
		}
		return true
	}catch(Exception  e){
		e.printStackTrace()
	}
	return false
}
複製代碼

此外,咱們也能夠經過 withObjectOutputStream/withObjectInputStream 來保存與讀取 Object 對象

//保存對象到文件中
task saveObject(){
	Person p=new Person()
	p.name="alan"
	p.age=18
	try{
		def desFile=new File("./person.txt")
		if(!desFile.exists()){
			desFile.createNewFile()
		}
		desFile.withObjectOutputStream{ out ->
			out.writeObject(p)
		}
		return true
	}catch(Exception e){
		e.printStackTrace()
	}
	return false
}

//從文件中讀取Object
task readObject(){
	println "readObject start"
	def obj=null
	try{
		def file=new File("./person.txt")
		if(file==null || !file.exists())
			println "file==null"
			return null
		file.withObjectInputStream{input ->
			obj=input.readObject()
			if(obj!=null){
				println "name=$obj.name"
				println "age=$obj.age"
			}else{
				println "obj==null"
			}
		}
		
	}catch(Exception e){
		e.printStackTrace()
	}
	println "readObject end"
}



class Person{
	private String name
	private int age
}
//讀寫的對象須要支持序列化,不然會報java.io.NotSerializableException

複製代碼

我是今陽,若是想要進階和了解更多的乾貨,歡迎關注個人公衆號接收到的個人最新文章

相關文章
相關標籤/搜索