Gradle之Groovy

Gradle之Groovy

作为一名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环境搭建

官网:http://www.groovy-lang.org/

https://groovy.apache.org/download.html

  1. 安装JDK
  2. 到官网下载groovySDK,解压到合适位置
  3. 配置环境变量

无论mac/linux还是window都是这三步只不过每个平台上的步骤不一样,学啥语言的都跑不过这几步。

4 Hello Groovy

学习一个语言基本都是从Hello World开始

开发一个Groovy程序可以使用intellij idea这个编译器,https://www.jetbrains.com/idea/ 直接去官网下载社区版就可以了,社区版支持Groovy程序的开发。

Groovy和Java完全兼容,所以我们完全可以使用Java代码来编写Groovy程序

在intellij idea中新建一个Groovy程序(在新建项目面板的右上角,Groovy library选项中添加下载的groovySDK的路径),在src文件夹下面新建一个Groovy的class类,写下面Java代码

1
2
3
4
5
class GroovyTest {
public static void main(String[] args){
System.out.print("Hello Groovy");
}
}

可以直接运行,输出: Hello Groovy

不过我们是来学Groovy语言的,当然用Groovy来写会更简单,简单到啥程度呢,把上面代码全删了,写下面一句。

1
print("Hello Groovy")

直接运行 输出:Hello Groovy

看起来很爽啊!

5 Groovy 语法练习

5.1 变量

groovy中的变量包括 基本类型 ,对象类型,不过groovy中所有类型都是对象类型。基本类型也会被自动装箱成对象类型比如:

1
2
3
4
int a = 2;
print(a.class)

输出结果:class java.lang.Integer

变量的定义:

定义一个变量不仅可以使用强类型定义,也可以使用弱类型定义。比如即可以使用int,double这些来修饰一个变量,也可以直接用def来修饰一个变量,使用def修饰,系统会自动推导类型,比如:

1
2
3
4
5
6
7
8
9
10
11
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"(可扩展)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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 哈哈
23=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)包括普通类型的参数和闭包类型的参数

常用的普通类型参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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中更强大

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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循环

1
2
3
4
5
6
7
8
9
10
11
12
13
//循环一个范围
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 闭包的概念:就是一个代码块

闭包的定义和调用:

1
2
3
4
def closure = {println "hello groovy"}
//两种调用的方法
closure.call()
closure()

闭包的参数:

1
2
3
4
def closure2 = { println "hello ${it}"}
closure2("groovy")
def closure1 = {String name,int age -> println "hello ${name},age ${age}"}
closure1("groovy",15)

会有一个默认的参数,可以使用it这个关键字来接收,如果有多个参数可以使用->来隔开

闭包的返回值

1
2
3
def closure2 = { return  "hello ${it}"}
def b = closure2("groovy")
println(b)

如果不定义return,默认返回的是null

5.4.2 闭包的使用

闭包与基本类型结合使用:

常用方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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))

闭包与字符串结合使用:

常用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
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

1
2
3
4
5
6
7
8
9
10
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

1
2
3
4
5
6
7
8
9
10
11
12
13
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可以动态的改变,改变之后可以让一个对象指向另一个对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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 列表

列表的定义

1
2
3
4
5
6
7
//java的方式定义
def list = new ArrayList()
//groovy的方式定义 它默认也是一个ArrayList
def list1 = [1,2,3]
//定义一个数组
def arr = [1,2,3] as int[]
int[] arr1 = [1,2,3]

列表的操作

增删

1
2
3
4
5
6
7
8
9
10
11
12
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)

排序操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//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的定义和使用

1
2
3
4
5
6
7
8
9
10
11
12
//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的常用操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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的定义和使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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中元编程

当调用一个类的方法的时候:

  1. 该类中是否有此方法 有直接调用,没有去MetaClass中查找是否有
  2. MetaClass中有调用MeatClass中的方法,没有看是否重写了methodMissing()方法,写了调用该方法,没写,看是否重写了invoke()方法
  3. 写了自行invoke方法,没写抛出异常(MissingMethodExecption)

动态添加属性或者方法,可以扩展一些引入的第三方包中的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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的方式非常简单

1
2
3
4
5
6
7
8
9
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的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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中也有自己的封装的简单的方法

读取项目跟目录下的一个文件并遍历

1
2
def file = new File('../MyGroovy.iml')
file.each {line -> println(line)}

读取内容为一个text

1
2
def text = file.getText()
println(text)

读取部分内容

1
2
3
4
5
6
def reader = file.withReader { reader ->
char[] buffer = new char[100]
reader.read(buffer)
return buffer
}
println(reader)

文件写入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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)

对象的保存和读取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//保存对象
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)

# 架构

コメント

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×