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

复制代码

我是今阳,若是想要进阶和了解更多的干货,欢迎关注个人公众号接收到的个人最新文章

相关文章
相关标签/搜索