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
- 安装JDK
- 到官网下载groovySDK,解压到合适位置
- 配置环境变量
无论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
5class 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
4int a = 2;
print(a.class)
输出结果:class java.lang.Integer
变量的定义:
定义一个变量不仅可以使用强类型定义,也可以使用弱类型定义。比如即可以使用int,double这些来修饰一个变量,也可以直接用def来修饰一个变量,使用def修饰,系统会自动推导类型,比如:1
2
3
4
5
6
7
8
9
10
11def 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 | def name1 = 'i am name1' |
从上面的输出内容还可以看出:一个双引号定义的字符串的类型是java.lang.String,当经过${}符号运算过之后变成了org.codehaus.groovy.runtime.GStringImpl类型。虽然类型变了,在平时的程序中这两个类型一般可以互相使用。
5.2.2 GString的操作符
GString的操作符比Java中的String中的方法多,只要来源是:
- java.long.String
- DefaultGroovyMethods
- StringGroovyMethods(继承DefaultGroovyMethods)包括普通类型的参数和闭包类型的参数
常用的普通类型参数:
1 | def str = "hello groovy" |
5.3 逻辑控制
switch/case 和java中不一样 比java中更强大
1 | def x = 12 |
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
4def closure = {println "hello groovy"}
//两种调用的方法
closure.call()
closure()
闭包的参数:1
2
3
4def closure2 = { println "hello ${it}"}
closure2("groovy")
def closure1 = {String name,int age -> println "hello ${name},age ${age}"}
closure1("groovy",15)
会有一个默认的参数,可以使用it
这个关键字来接收,如果有多个参数可以使用->
来隔开
闭包的返回值1
2
3def 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
25def 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
13def 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 | def clouser = { |
从打印来看都是一样的,那他们有什么区别呢?
this:代表闭包定义处的类
owner:代表闭包定义处的类或者对象
delegate:代表任意对象 默认是owner
1 | def outClouser = { |
闭包的委托策略:
delegate可以动态的改变,改变之后可以让一个对象指向另一个对象。
1 | class Teacher{ |
5.5 常用的数据结构
5.5.1 列表
列表的定义
1 | //java的方式定义 |
列表的操作
增删
1 | def list = [3,2,4,1,5,9,7,8] |
排序操作
1 | //java中的排序---------- |
5.5.1 Map
Map的定义和使用
1 | //java方式 |
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
23def 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 | def range = 1..10 |
5.7 面向对象
类默认都是public的
1 | interface IAction { |
groovy中元编程
当调用一个类的方法的时候:
- 该类中是否有此方法 有直接调用,没有去MetaClass中查找是否有
- MetaClass中有调用MeatClass中的方法,没有看是否重写了methodMissing()方法,写了调用该方法,没写,看是否重写了invoke()方法
- 写了自行invoke方法,没写抛出异常(MissingMethodExecption)
动态添加属性或者方法,可以扩展一些引入的第三方包中的类
1 | def person = new Person(name: 'lily',age: 15) |
6 Groovy高级语法
6.1 groovy 对 json的操作
groovy中自带的操作json的方式非常简单
1 | def list = [new Person(name: 'lily',age: 15),new Person(name: 'jack',age: 16)] |
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
31final 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
22import 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)
通过类自动生成xml1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26import 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
2def file = new File('../MyGroovy.iml')
file.each {line -> println(line)}
读取内容为一个text1
2def text = file.getText()
println(text)
读取部分内容1
2
3
4
5
6def 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
28def 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)