作为一名Android开发者,每天使用AndroidStudio,对于项目中build.gradle文件肯定不陌生,里面有各种各样的配置。对于一些常用的配置我们肯定烂熟于心,不过有时候去看一些大厂的代码的时候,经常会发现他们的项目中有很多的gradle的代码,我们往往因为不了解这些而对了解优秀的项目而带来一些障碍。
百度百科:Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化构建开源工具。它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,目前也增加了基于Kotlin语言的kotlin-based DSL,抛弃了基于XML的各种繁琐配置。
1 DSL语言介绍
domain specific language(领域特定语言 )
DSL语言特点:解决计算机某一特定领域的问题
核心思想:求专不求多
我们常见的UML,XML,HTML等都是DSL语言,他们都是专注于特定的领域来解决特定的问题。比如HTML就是为了布局UI。因为专注,所以有很多优点比如代码少,效率高。
2 groovy语言
啥是groovy
- groovy是一种基于JVM的敏捷开发语言
- 结合了Python Ruby Smalltalk等语言的强大特性
- groovy可以和Java完美结合,可以使用Java所有的类库,也能用于扩展现有代码。
groovy的特性
- 语法上支持动态类型,闭包等新一代语言的特性
- 可以无缝集成左右已经存在的Java的类库
- 即支持面向对象编程,也支持面向过程编程
groovy的优势
- 它是一种更加敏捷的编程语言,可以用更少的代码完成Java同样的功能
- 对于Java程序员来说,入门容易,功能强大
- 即可以作为编程语言,也可以作为脚本语言
3 groovy环境搭建
groovy.apache.org/download.ht…
- 安装JDK
- 到官网下载groovySDK,解压到合适位置
- 配置环境变量
无论mac/linux还是window都是这三步只不过每个平台上的步骤不一样,学啥语言的都跑不过这几步。
4 Hello Groovy
学习一个语言基本都是从Hello World开始
开发一个Groovy程序可以使用intellij idea这个编译器,www.jetbrains.com/idea/ 直接去官网下载社区版就可以了,社区版支持Groovy程序的开发。
Groovy和Java完全兼容,所以我们完全可以使用Java代码来编写Groovy程序
在intellij idea中新建一个Groovy程序(在新建项目面板的右上角,Groovy library选项中添加下载的groovySDK的路径),在src文件夹下面新建一个Groovy的class类,写下面Java代码
class GroovyTest {
public static void main(String[] args){
System.out.print("Hello Groovy");
}
}
可以直接运行,输出: Hello Groovy
不过我们是来学Groovy语言的,当然用Groovy来写会更简单,简单到啥程度呢,把上面代码全删了,写下面一句。
print("Hello Groovy")
直接运行 输出:Hello Groovy
看起来很爽啊!
5 Groovy 语法练习
5.1 变量
groovy中的变量包括 基本类型 ,对象类型,不过groovy中所有类型都是对象类型。基本类型也会被自动装箱成对象类型比如:
int a = 2;
print(a.class)
输出结果:class java.lang.Integer
变量的定义:
定义一个变量不仅可以使用强类型定义,也可以使用弱类型定义。比如即可以使用int,double这些来修饰一个变量,也可以直接用def来修饰一个变量,使用def修饰,系统会自动推导类型,比如:
def b = 3
println b.class
def c = 3.14
println c.class
def d = "groovy"
println d.class
输出结果:
class java.lang.Integerclass java.lang.Integer
class java.math.BigDecimal
class java.lang.String
一般情况下,如果我们是自己在写一个程序,使用def来定义一个变量会很简单,如果程序还需要提供给外部人员使用,那使用强类型来定义比较好,不然外部人员可能会比较疑惑需要传什么类型的变量。
5.2 字符串
Java中是String
Groovy中是GString
5.2.1 Groovy常用的定义方式:
- 使用单引号
def name1 = 'i am name1'效果和java中一模一样(不可扩展) - 使用三个引号
def name = '''i am name''',使用三个引号的字符串我们可以在字符串内部保留字符串的格式,比如可以随便换行 - 使用双引号定义字符串
def name3 = "i am name3"(可扩展)
def name1 = 'i am name1'
def name2 = '''i am name2
hello name2
hai name2
'''
println(name2)
def name3 = "i am name3"
def name4 = "${name3} 哈哈"
println(name4)
//${}中可以是任意的表达式,比如
def sum = "2加3=${2+3}"
println(sum)
println(name3.class)
println(sum.class)
输出:
i am name2
hello name2
hai name2
i am name3 哈哈
2加3=5
class java.lang.String
class org.codehaus.groovy.runtime.GStringImpl
从上面的输出内容还可以看出:一个双引号定义的字符串的类型是java.lang.String,当经过${}符号运算过之后变成了org.codehaus.groovy.runtime.GStringImpl类型。虽然类型变了,在平时的程序中这两个类型一般可以互相使用。
5.2.2 GString的操作符
GString的操作符比Java中的String中的方法多,只要来源是:
- java.long.String
- DefaultGroovyMethods
- StringGroovyMethods(继承DefaultGroovyMethods)包括普通类型的参数和闭包类型的参数
常用的普通类型参数:
def str = "hello groovy"
def str1 = "hello"
def str2 = "123"
println(str.center(15,'a'))//总长度15,在原字符串两端加a
println(str.padLeft(15,'a'))//总长度15,在原字符串左边加a
println(str>str1)
println(str[0])
println(str[0..1])
println(str.reverse())
println(str.capitalize())
println(str2.isNumber())
println(str2.toInteger())
输出:
ahello groovyaa
aaahello groovy
true
h
he
yvoorg olleh
Hello groovy
true
123
5.3 逻辑控制
switch/case 和java中不一样 比java中更强大
def x = 12
def res
switch (x){
case 'string':
res = 'string'
break
case [3,4,5,6,"haha"]://列表类型
res = 'string'
break
case Integer:
res = 'Integer'
break
case BigDecimal:
res = 'BigDecimal'
break
case 9..30: //表示一个范围
res = 'string'
break
default: 'default'
}
println(res)
for循环
//循环一个范围
for (i in 0..9){
println(i)
}
//循环一个list
for (i in [3,4,5,6,7,8,9,0]){
println(i)
}
//循环一个map
for (i in ["lily":18,"divad":19,"xiaoming":20]){
println(i.key)
println(i.value)
}
while循环、if/else和java中一样
5.4 闭包
闭包是groovy最强大的功能之一
5.4.1 闭包的概念:就是一个代码块
闭包的定义和调用:
def closure = {println "hello groovy"}
//两种调用的方法
closure.call()
closure()
闭包的参数:
def closure2 = { println "hello ${it}"}
closure2("groovy")
def closure1 = {String name,int age -> println "hello ${name},age ${age}"}
closure1("groovy",15)
会有一个默认的参数,可以使用it这个关键字来接收,如果有多个参数可以使用->来隔开
闭包的返回值
def closure2 = { return "hello ${it}"}
def b = closure2("groovy")
println(b)
如果不定义return,默认返回的是null
5.4.2 闭包的使用
闭包与基本类型结合使用:
常用方法:
def x = 5
//求阶乘
def jiecheng(int num){
int res = 1
//upto里面实现了循环
1.upto(num,{n -> res*=n})
return res
}
//求阶乘
def jiecheng1(int num){
int res = 1
num.downto(1){
n -> res *= n
}
return res
}
//累加
def leijia(int num){
int res = 1
num.times {n -> res +=n}
return res
}
println(jiecheng(x))
println(jiecheng1(x))
println(leijia(5))
闭包与字符串结合使用:
常用方法
def str = 'hello groovy 1 2 3'
//each 遍历
str.each { String tem -> println(tem.capitalize()) }
//找到第一个满足条件的 并返回
println str.find{ String tem -> tem.isNumber()}
//找到所有满足条件的 并返回
println str.findAll(){ String tem -> tem.isNumber()}
//只要字符串中存在数字 就返回true
println str.any{ String s -> s.isNumber()}
//字符串每个元素都是数字 就返回true
println(str.every {String s -> s.isNumber()})
//搜集所有字符 并大写 放到list中返回
println str.collect {String s -> s.toUpperCase()}
5.4.3 闭包的进阶
闭包关键变量 this, owner,delegate
def clouser = {
println("this:" + this)
println("owner:" + owner)
println("delegate:" + delegate)
}
clouser.call()
输出:
this:GroovyTest@741a8937
owner:GroovyTest@741a8937
delegate:GroovyTest@741a8937
从打印来看都是一样的,那他们有什么区别呢?
this:代表闭包定义处的类
owner:代表闭包定义处的类或者对象
delegate:代表任意对象 默认是owner
def outClouser = {
def innerClouser = {
println("this:" + this)
println("owner:" + owner)
println("delegate:" + delegate)
}
innerClouser.call()
}
outClouser.call()
输出:
this:GroovyTest@306e95ec
owner:GroovyTest$_run_closure1@43dac38f
delegate:GroovyTest$_run_closure1@43dac38f
闭包的委托策略:
delegate可以动态的改变,改变之后可以让一个对象指向另一个对象。
class Teacher{
String name
def nameStr = {"my name is ${name}"}
@Override
String toString() {
return nameStr.call()
}
}
class Student{
String name
}
Teacher teacher = new Teacher(name: "teacher")
Student student = new Student(name: "student")
teacher.nameStr.delegate = student
teacher.nameStr.resolveStrategy = Closure.DELEGATE_FIRST
println teacher.toString()
输出:
my name is student
5.5 常用的数据结构
5.5.1 列表
列表的定义
//java的方式定义
def list = new ArrayList()
//groovy的方式定义 它默认也是一个ArrayList
def list1 = [1,2,3]
//定义一个数组
def arr = [1,2,3] as int[]
int[] arr1 = [1,2,3]
列表的操作
增删
def list = [3,2,4,1,5,9,7,8]
list.add(0)
//追加
list.leftShift(6)
//追加
list << 6
//删除
//list.remove(1)
//list.removeAt(1)
//删除所有偶数
list.removeAll {return it%2==0}
println(list)
排序操作
//java中的排序----------
def sortList = [3,5,2,1,-3,-6,-4]
//Collections.sort(sortList)
//println(sortList)
//自定义排序规则
//Comparator comparator = {a,b->a==b?0:Math.abs(a)>Math.abs(b)?1:-1}
//Collections.sort(sortList,comparator)
//println(sortList)
//groovy中的排序-----------
sortList.sort()
//自定义排序规则
sortList.sort(){a,b->a==b?0:Math.abs(a)>Math.abs(b)?1:-1}
println(sortList)
//字符串列表
def stringList = ['hello','ab','a','cde','groovy']
stringList.sort(){it -> return it.size()}
println(stringList)
def findList = [5,6,3,2,1,9,8]
//查找第一个奇数
def res = findList.find(){return it%2 == 1}
//查找所有的奇数
def res1 = findList.findAll(){return it%2 == 1}
//判断是否有奇数
def res2 = findList.any(){return it%2 == 1}
//判断是不是全是奇数
def res3 = findList.every(){return it%2 == 1}
println(res3)
println(findList.min())
println(findList.max())
println(findList.min{return Math.abs(it)})
//统计查找偶数的个数
def num = findList.count{ return it%2==0 }
println(num)
5.5.1 Map
Map的定义和使用
//java方式
def map = new HashMap()
//groovy方式
def map1 = ['lily':15,'jack':16,'divad':17]
//查找元素
println(map1['lily'])
//添加元素
map1.xiaoming = 18
println(map1.toMapString())
//添加不同类型的元素
map1.sub = ['a':1,'b':2]
println(map1.toMapString())
groovy中的Map默认是Java中LinkedHashMap
Map的常用操作
def map = ['lily':15,'jack':16,'divad':17,'xiao':14]
//遍历
map.each {def person -> println "key:${person.key} value:${person.value}"}
map.each {key,value -> println "key:${key} value:${value}"}
//有下标的遍历
map.eachWithIndex {def person ,int index -> println "key:${person.key} value:${person.value} index:${index}"}
map.eachWithIndex{key,value,index -> println "key:${key} value:${value} index:${index}"}
//查找第一个年龄大于15的
def res = map.find{def person -> person.value>15}
//查找所有年龄大于15的
def res1 = map.findAll{def person -> person.value>15}
//统计大于年龄15的个数
def num = map.count {return it.value>15}
//查找并分组
def group = map.groupBy {return it.value>15?'man':'child'}
println(group.toMapString())
//排序
def sort = map.sort{ def v1,def v2 ->
return v1.value == v2.value?0:v1.value>v2.value?1:-1
}
println(sort)
5.6 范围 Range
Range是一个轻量级的list,在有些简单的地方使用会比list更加方便
Range的定义和使用
def range = 1..10
println(range[0])
println(range.from)
println(range.to)
println(range.contains(11))
range.each {println(it)}
for (i in range) {
println(i)
}
def res = getGrade(85)
println(res)
def getGrade(int num){
def result
switch (num){
case 0..60:
result = '及格'
break
case 60..80:
result = '良好'
break
case 80..100:
result = '优秀'
break
}
return result
}
5.7 面向对象
类默认都是public的
interface IAction {
void eat()
void drink()
}
class Person implements IAction{
String name
int age
def increaseAge(int num){
this.age += num
}
@Override
void eat() {
}
@Override
void drink() {
}
}
def person = new Person(name: 'lily',age: 15)
person.increaseAge(10)
println("name: ${person.name} age: ${person.age}")
groovy中元编程
当调用一个类的方法的时候:
- 该类中是否有此方法 有直接调用,没有去MetaClass中查找是否有
- MetaClass中有调用MeatClass中的方法,没有看是否重写了methodMissing()方法,写了调用该方法,没写,看是否重写了invoke()方法
- 写了自行invoke方法,没写抛出异常(MissingMethodExecption)
动态添加属性或者方法,可以扩展一些引入的第三方包中的类
def person = new Person(name: 'lily',age: 15)
person.increaseAge(10)
person.cry()
//给一个类动态注入一个属性
Person.metaClass.sex = 'male'
def person1 = new Person(name: 'lily',age: 15)
println(person1.sex)
//给一个类动态添加一个方法
Person.metaClass.sexUpperCase = { -> sex.toUpperCase()}
def person2 = new Person(name: 'lily',age: 15)
println(person2.sexUpperCase())
//给一个类动态添加一个静态方法
Person.metaClass.static.createPerson = {
name,age -> return new Person(name:name,age: age)
}
def person3 = Person.createPerson('lily',15)
println("name:${person3.name}")
6 Groovy高级语法
6.1 groovy 对 json的操作
groovy中自带的操作json的方式非常简单
def list = [new Person(name: 'lily',age: 15),new Person(name: 'jack',age: 16)]
//对象转成json
String json = JsonOutput.toJson(list)
println(json)
//json转成对象
def jsonSlurper = new JsonSlurper()
println jsonSlurper.parseText(json)
//parse方法有很多重载的方法,可传入不同的值
jsonSlurper.parse()
jsonSlurper.parse()方法有很多重载的方法,可传入不同的值
6.2 groovy处理xml
解析xml的数据
final String xml = '''<apps>
<app>
<id>1</id>
<name>Google Maps</name>
<virsion>1.0</virsion>
</app>
<app>
<id>2</id>
<name>Chrome</name>
<version>2.1</version>
</app>
<app>
<id>3</id>
<name>Google Play</name>
<version>2.3</version>
</app>
</apps>
'''
def xmlSlurper = new XmlSlurper()
//返回的是xml的根节点
def apps = xmlSlurper.parseText(xml)
println(apps.app[0].name.text())
//深度遍历
def res = apps.depthFirst().findAll { app ->
return app.name.text()
}
def res1 = apps.children().findAll { app -> app.name() == 'app' }.collect {
app -> return app.name.text()
}
println(res)
println(res1)
生成xml的数据
import groovy.xml.MarkupBuilder
def sw = new StringWriter()
def xmlBuilder = new MarkupBuilder()
xmlBuilder.apps(type:'1'){
app(){
id(1)
name('Google Maps')
version(2.0)
}
app(){
id(2)
name('Chrome')
version(1.0)
}
app(){
id(3)
name('Google Play')
version(3.0)
}
}
println(sw)
通过类自动生成xml
import groovy.xml.MarkupBuilder
def sw = new StringWriter()
def xmlBuilder = new MarkupBuilder()
class apps{
String type = '1'
def apps = [new appsub(id: 1,name: 'Google Play',version: '1.0'),
new appsub(id: 1,name: 'java',version: '2.0'),
new appsub(id: 1,name: 'Google map',version: '3.0')]
}
class appsub{
int id
String name
String version
}
def apps = new apps()
xmlBuilder.apps(type:apps.type){
apps.apps.each { sub ->
appsub(){
id(sub.id)
name(sub.name)
version(sub.version)
}
}
}
println(sw)
6.3 groovy处理文件
所有java中的处理文件的方式都可以使用 groovy中也有自己的封装的简单的方法
读取项目跟目录下的一个文件并遍历
def file = new File('../MyGroovy.iml')
file.each {line -> println(line)}
读取内容为一个text
def text = file.getText()
println(text)
读取部分内容
def reader = file.withReader { reader ->
char[] buffer = new char[100]
reader.read(buffer)
return buffer
}
println(reader)
文件写入
def copy(String fromDir,String toDir){
try {
//创建目标文件
def toFile = new File(toDir)
if(!toFile.exists()){
toFile.createNewFile()
}
//开始copy
def fromFile = new File(fromDir);
if(fromFile.exists()){
fromFile.withReader { reader ->
def lines = reader.readLines()
toFile.withWriter { write->
lines.each {
line->
write.append(line + "\r\n")
}
}
}
}
return true
}catch (Exception e){
e.printStackTrace()
}
return false
}
def copres = copy('../MyGroovy.iml','../MyGroovy.iml2')
println(copres)
对象的保存和读取
//保存对象
def saveObject(Object obj,String path){
try {
//创建目标文件
def toFile = new File(path)
if(!toFile.exists()){
toFile.createNewFile()
}
toFile.withObjectOutputStream {out->
out.writeObject(obj)
}
return true
}catch (Exception e){
e.printStackTrace()
}
return false
}
//读取对象
def readObj(String path){
def obj = null
try {
def file = new File(path)
if(file==null||!file.exists()) return null
file.withObjectInputStream {
input->
obj = input.readObject()
}
return obj
}catch (Exception e){
e.printStackTrace()
}
return null
}
def person = new Person(name: '大海',age: 15)
def res = saveObject(person,'../person.bin')
println(res)
def personRes = (Person)readObj('../person.bin')
println(personRes.name)