【gradle使用前篇—Groovy简介】
Groovy介绍
Groovy是一种动态语言,对它的定义是:Groovy是在java平台上的,具有像Python、Ruby和smalltalk语言特性的灵活动态语言,Groovy保证了这些特性像java语言一样被java开发者使用。说白了就是让写java程序变的像写脚本一样简单,Groovy内部会将其编译成java class,然后放到JVM上执行。
此外Groovy是一种DSL(Domain Specific Language),是针对某个领域所涉及出来的一个特定的语言,因为有了领域的限制,要解决的问题就被划定了范围,所以语言不需要复杂,就可以具有精确的表达能力,使用起来非常方便。更具体的来说:使用java或者C++也能够实现相同的功能,但是会产生大量繁琐的代码并导致大量的领域知识被隐藏在通用语言构造中(比如:for循环、if条件等等)。(关于DSL感兴趣的,可以自己Google,可以深入学习下怎么定义自己的DSL语言)。
1 语法基础
1)注释
Groovy的单行注释、多行注释、文档注释和java一样。只有一种特殊的单行注释需要留意:
#!/usr/bin/env groovy
println "Hello from the shebang line"
这种注释在脚本中经常见到,一般都是固定写法。
2)关键字
Groovy有如下的关键字:
as、assert、break、case、catch、class、const、continue、def、default、do、else、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。
看到了吧,其实它和java的关键字区别不大,其中不一样的关键字是:
- def用来定义一个变量,定义变量时可以不指定类型。
- goto在java中是保留关键字
- assert常用在C或者C++中
- trait是一组可重用的方法和字段,可以将他们混入一个或者多个类中,一个类可以同时拥有多个trait而不需要使用多重继承。
- 其他关键字可能有的略有不同,在使用过程中可以再了解。
3)标识符
- 普通标识符和常用语言类似,只能以字母、美元符号、下划线开始,不能以数字开始
- 引用标识符出现在点后的表达式中,比如:
def map = [:]
//引用标示符中出现空格也是对的
map."an identifier with a space and double quotes" = "ALLOWED"
//引用标示符中出现横线也是对的
map.'with-dash-signs-and-single-quotes' = "ALLOWED" assert map."an identifier with a space and double quotes" == "ALLOWED"
assert map.'with-dash-signs-and-single-quotes' == "ALLOWED"
Groovy的所有字符串都可以当作引用标识符定义,如下:
//如下类型字符串作为引用标识符都是对的
map.'single quote'
map."double quote"
map.'''triple single quote''' //三个引号的,可以换行显示
map."""triple double quote"""
map./slashy string/
map.$/dollar slashy string/$ //稍微特殊的GString,也是对的
def firstname = "Homer"
map."Simson-${firstname}" = "Homer Simson" assert map.'Simson-Homer' == "Homer Simson"
4)字符及字符串
- 单引号字符串是String类型的,不支持占位符,比如
def name = 'Test Groovy!'
def body = 'Test $name' assert name == 'Test Groovy!'
assert body == 'Test $name' //不会替换$name站位符 字符串可以通过 + 直接拼接。
- 三重单引号字符串是String类型的,不支持占位符插值操作,可以标识多行字符串,比如:
def aMultilineString = '''line one
line two
line three'''
- 双引号字符串支持占位插值操作,如果双引号字符串不包含占位符则是String类型的,如果双引号字符中包含占位符则是GString类型的。对于插值占位符我们可以使用${}或者$表示,${}用于一般替代字符串或者表达式,$主要用于A.B的形式中,比如:
def name = 'Guillaume' // a plain string
def greeting = "Hello ${name}"
assert greeting.toString() == 'Hello Guillaume' def sum = "The sum of 2 and 3 equals ${2 + 3}"
assert sum.toString() == 'The sum of 2 and 3 equals 5' def person = [name: 'Guillaume', age: 36]
assert "$person.name is $person.age years old" == 'Guillaume is 36 years old' //注意的是:$只对A.B等有效,如果表达式包含括号、大括号、闭包等符号则是无效的。比如: def number = 3.14 shouldFail(MissingPropertyException) { println "$number.toString()" } //该代码运行抛出groovy.lang.MissingPropertyException异常,因为Groovy认为去寻找number的名为toString的属性,所以异常
- 还有一个很NB的结论,一个普通插值表达式替换实际是在GString创建的时刻,一个包含闭包的表达式由于延迟运算调用toString()方法,所以会产生一个新的字符串值。
def number = 1
def eagerGString = "value == ${number}"
def lazyGString = "value == ${ -> number }" assert eagerGString == "value == 1"
assert lazyGString == "value == 1"
// 当number = 2 时,两者出现了不同
number = 2
assert eagerGString == "value == 1"
assert lazyGString == "value == 2"
- GString和String的hashCode是不一样的。
- 多重双引号字符串也支持占位插值操作。
- 斜线字符串和双引号字符串类似,通常用在正则表达式中。
//普通使用
def fooPattern = /.*foo.*/
assert fooPattern == '.*foo.*'
//含转义字符使用
def escapeSlash = /The character \/ is a forward slash/
assert escapeSlash == 'The character / is a forward slash'
//多行支持
def multilineSlashy = /one
two
three/ assert multilineSlashy.contains('\n')
//含站位符使用支持
def color = 'blue'
def interpolatedSlashy = /a ${color} car/ assert interpolatedSlashy == 'a blue car'
- Groovy没有明确的Characters,但是我们可以用如下三种方式处理字符
char c1 = 'A'
assert c1 instanceof Character def c2 = 'B' as char
assert c2 instanceof Character def c3 = (char)'C'
assert c3 instanceof Character
5)Lists类型
Groovy支持List类型,可以增加或者删除对象,列表中的对象不受类型限制,比较特殊的是可以通过超出列表范围的数字来索引列表。可以做个小例子:
//和java中的思想是一样的
def numbers=[1,2,3];
assert numbers instanceof List
assert numbers.size() == 3 //存储任意类型
def test = [1, 'a', true] //使用as强制类型转换
def linkedList = [2,3,4] as LinkedList
assert linkedList instanceof java.util.LinkedList //给List追加item
def letters = ['a', 'b','c','c']
letters << 'e'
assert letters[4] == 'e' //多维List支持
def multi = [[0, 1], [2, 3]]
assert multi[1][0] == 2
6)Map类型
Map是“键-值”对的集合,在Groovy中键key不一定是String,可以是任意对象。
def colors=[red:'1',green:'2', blue:'3']
assert colors.red == '1' //对于map需要特别注意一种情况,如下:
//把一个定义的变量作为Map的key的正确写法---添加括弧,访问Map的该key是成功的
def key = 'name'
def person=[(key):'liwei']
assert !person.containsKey('key')
assert person.containsKey('name')
7)Range类
Range是Groovy对List的一种拓展:
def aRange = 1..5 <==Range类型的变量 由begin值+两个点+end值表示
左边这个aRange包含1,2,3,4,5这5个值 如果不想包含最后一个元素,则 def aRangeWithoutEnd = 1..<5 <==包含1,2,3,4这4个元素
println aRange.from
println aRange.to
2 闭包
1)闭包(Closure)的定义
闭包是Groovy中非常重要的一个数据类型或者说一个概念。它代表了一段可执行的代码,其外形如下:
def aClosure = {//闭包是一段代码,所以需要用花括号括起来..
String param1, int param2 -> //这个箭头很关键。箭头前面是参数定义,箭头后面是代码
println"this is code" //这是代码,最后一句是返回值,
//也可以使用return,和Groovy中普通函数一样
} //简而言之,闭包的定义格式是:
def xxx={paramters ——> code}
def xxx={无参数,纯code} 这种case不需要 ——>符号 //调用闭包的方式:
xxx.call(paramter1,paramter2...)
xxx(paramter1,paramter2....) //如果闭包没有定义参数的话,则隐含有一个参数,这个参数交 it, 和java中this类似。
def xxx = {“Hello,$it!”}
assert xxx('Groovy') == 'Hello Groovy!' //不过如果想定义的本来就是没有参数,则可以定义如下
def noParamClosure = {—> true}
2)使用中注意的点
- 省略圆括号
//闭包在Groovy中大量使用,比如下面这个函数,最后一个参数是闭包
public static <T> List<T> each(List<T> self, Closure closure) //上面这个方法是List中的,表示可以对List中每一个元素在闭包中做一些处理,我们看下如何使用它:
def iamList = [1,2,3,4,5] //定义一个List
//这里有有两个知识点:
iamList.each{ //调用它的each,这段代码的格式看不懂了吧?each是个函数,圆括号去哪了?
println it
}
1)Groovy中,当函数的最后一个参数是闭包的话,可以省略圆括号。
2)如何确定Closure参数 我们还以上面的那个iamList为例,通过查看API可以知道 【递归set中的元素,传递每一个item给闭包】
所以参数其实就明确了,是List中的每一个元素。
同理我们也可以得出,对于Map来说,它的类似方法中的闭包可以有两个参数,以findAll为例,会将
key和Value分别传进去。 从这里我们可以看出,一定要对API熟悉,才能很好的使用闭包。 //我们在平时的gradle项目中也常常见到
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
3 脚本类、文件IO和XML操作
1)脚本类
- 脚本中import其他类
在Groovy中,系统自带会加载当前目录及其子目录下的xxx.groovy文件。
- 脚本到底是什么
当通过 groovy xxx.groovy运行脚本时,Groovy会先把xxx.groovy中的内容转换成一个java类(groovyc -d classes test.groovy)。这个java类有以下特点:
1. xxx.groovy被转换成一个test类,继承script
2. 每一个脚本都会生成一个static main 函数,所以当执行 groovy test.groovy时,其实就是执行了main方法
3. 脚本中所有代码都会放到run方法中。
4. 如果脚本中定义了函数,则函数会被定义在test类中。
- 脚本中的变量和作用域
def x = 1 <==注意,这个x有def(或者指明类型,比如 int x = 1)
def printx(){
println x //这里会报错,提示x找不到
} //其实从上面的介绍已经可以知道为啥这里为啥报错了。
原因就是:printx方法在类中是一个成员函数,但是x会被放到 run方法中,所以printx方法是不可能访问到x元素的。
2)文件I/O操作
- 读文件
def targetFile=new File(文件名) //创建File对象 targetFile.eachLine{ //读文件中的每一行
String oneLine ->
println oneLine
} targetFile.getBytes() //文件一次性读出,返回类型为byte【】 def ism = targetFile.newInputStream() //流
ism.close targetFile.withInputStream{
ism ->
不需要close, Groovy会自动替你close
}
- 写文件
def srcFile = new File(源文件名)
def targetFile = new File(目标文件名)
targetFile.withOutputStream{ os->
srcFile.withInputStream{ ins->
os << ins //利用OutputStream的<<操作符重载,完成从inputstream到OutputStream
//的输出
}
}
3)XML操作
Groovy提供了一个GPath。直接上例子看下怎么用
<!--test.xml-->
<response version-api="2.0">
<value>
<books>
<book available="20" id="1">
<title>Don Xijote</title>
<author id="1">Manuel De Cervantes</author>
</book>
<book available="14" id="2">
<title>Catcher in the Rye</title>
<author id="2">JD Salinger</author>
</book>
<book available="13" id="3">
<title>Alice in Wonderland</title>
<author id="3">Lewis Carroll</author>
</book>
<book available="5" id="4">
<title>Don Xijote</title>
<author id="4">Manuel De Cervantes</author>
</book>
</books>
</value>
</response>
//第一步,创建XmlSlurper类
def xparser = new XmlSlurper()
def targetFile = new File("test.xml")
//轰轰的GPath出场
GPathResult gpathResult =xparser.parse(targetFile) //开始玩test.xml。现在我要访问id=4的book元素。
//下面这种搞法,gpathResult代表根元素response。通过e1.e2.e3这种
//格式就能访问到各级子元素....
def book4 = gpathResult.value.books.book[3]
//得到book4的author元素
def author = book4.author
//再来获取元素的属性和textvalue
assert author.text() == ' Manuel De Cervantes '
获取属性更直观
author.@id == '4' 或者 author['@id'] == '4'
属性一般是字符串,可通过toInteger转换成整数
author.@id.toInteger() == 4
好了。GPath就说到这。再看个例子。我在使用Gradle的时候有个需求,就是获取AndroidManifest.xml版本号(versionName)。有了GPath,一行代码搞定,请看:
def androidManifest = newXmlSlurper().parse("AndroidManifest.xml")
println androidManifest['@android:versionName']
或者
println androidManifest.@'android:versionName'
4 总结
Groovy是一门语言,因此一篇文章不可能表达的很清楚,只是作为入门教程,对Groovy有个大概的认识,为之后学习Gradle打基础,如果想更深入的了解Groovy,需要自行的实践和Google了。
参考博客:
http://www.infoq.com/cn/articles/android-in-depth-gradle/
api文档
http://tool.oschina.net/apidocs/apidoc?api=groovy
【gradle使用前篇—Groovy简介】的更多相关文章
- iOS开发UI篇—CALayer简介
iOS开发UI篇—CALayer简介 一.简单介绍 在iOS中,你能看得见摸得着的东西基本上都是UIView,比如一个按钮.一个文本标签.一个文本输入框.一个图标等等,这些都是UIView. 其实 ...
- VS2010+MVC4+Spring.NET2+NHibernate4-传统三层架构-前篇
VS2010+MVC4+Spring.NET2+NHibernate4 - 传统三层架构 - 前篇 一直追求使用开源项目,就因一个字:懒! 一直想整理一下的,却一直懒到现在!从当初用的MVC3到现在的 ...
- 【翻译】西川善司「实验做出的游戏图形」「GUILTY GEAR Xrd -SIGN-」中实现的「纯卡通动画的实时3D图形」的秘密,前篇(2)
Lighting和Shading(2)镜面反射的控制和模拟次级表面散射技术 http://www.4gamer.net/games/216/G021678/20140703095/index_2.ht ...
- iOS开发多线程篇—多线程简介
iOS开发多线程篇-多线程简介 一.进程和线程 1.什么是进程 进程是指在系统中正在执行的一个应用程序 每一个进程之间是独立的.每一个进程均执行在其专用且受保护的内存空间内 比方同一时候打开QQ.Xc ...
- ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇
原文:ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇 第三章 为控件添加事件 好了,我们之前以前开发一个控件.而且也添加了属性,开发也很规范,但是那个控件还差最后一点:添加事件. 系列 ...
- 【原创】构建高性能ASP.NET站点 第六章—性能瓶颈诊断与初步调优(下前篇)—简单的优化措施
原文:[原创]构建高性能ASP.NET站点 第六章-性能瓶颈诊断与初步调优(下前篇)-简单的优化措施 构建高性能ASP.NET站点 第六章—性能瓶颈诊断与初步调优(下前篇)—简单的优化措施 前言:本篇 ...
- [原创].NET 分布式架构开发实战之四 构建从理想和实现之间的桥梁(前篇)
原文:[原创].NET 分布式架构开发实战之四 构建从理想和实现之间的桥梁(前篇) .NET 分布式架构开发实战之四 构建从理想和实现之间的桥梁(前篇) 前言:上一篇文章讲述了一些实现DAL的理论,本 ...
- webpack2 前篇
webpack2 前篇 #webpack 前两天用了一天半时间琢磨了下webpack2,想起去年这时候,面对webpack1那样恶心的文档,前前后后搞了好几次才摸索清楚,那真是吐了. 划重点 其实we ...
- 文本分类需要CNN?No!fastText完美解决你的需求(前篇)
http://blog.csdn.net/weixin_36604953/article/details/78195462?locationNum=8&fps=1 文本分类需要CNN?No!f ...
随机推荐
- Spring Security 自定义登录认证(二)
一.前言 本篇文章将讲述Spring Security自定义登录认证校验用户名.密码,自定义密码加密方式,以及在前后端分离的情况下认证失败或成功处理返回json格式数据 温馨小提示:Spring Se ...
- Web Storage和cookie的区别——每日一题20190629
Web Storage? 使用HTML5可以在本地存储用户的浏览数据. 使用的主要目的是为了克服Cookie带来的一些限制,当数据需要被严格控制在客户端上时,无需持续的将数据发回服务器 主要目标: 1 ...
- 直线扫描转换-DDA算法
直线扫描转换-DDA算法 直线段的扫描转换算法 已知两个点,求直线. 为了在光栅显示器上用这些离散的像素点逼近这条直线,需要知道这些像素点的x,y坐标. 求出过P0,P1的直线段方程: y=kx+b ...
- maven解决无法从远程仓库获取ojdbc问题
原因 Oracle 的 ojdbc.jar 是收费的,Maven 中央库中实际上没有此资源 解决方法 手动下载相应的jar,然后将其安装到本地仓库.具体操作如下: 1\先去下载相关的jar包或者驱动 ...
- 算法学习之剑指offer(七)
题目1 题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P.并将P对1000000007取模的结果输出. 即输出P% ...
- js二次作业
task 1:完成省城市的三级联动(包括湖南省),附代码和效果图.<!DOCTYPE html> <html> <head> <title>完成省城市的 ...
- pdfminer API介绍:pdf网页爬虫
安装 pip install pdfminer 爬取数据是数据分析项目的第一个阶段,有的加密成pdf格式的文件,下载后需要解析,使用pdfminer工具. 先介绍一下什么是pdfminer 下面是官方 ...
- PHP array_mulitsort
1.函数的作用:对多维数组进行排序 2.函数的例子: 例子一: <?php // http://php.net/manual/zh/function.array-multisort.php $m ...
- JZOJ5771【NOIP2008模拟】遨游
Description MWH寒假外出旅游,来到了S国.S国划分为N个省,第i个省有Ti座城市,编号分别为Ci1,Ci2,……CiTi(各省城市编号不会重复).所有城市间有M条双向的道路连接 ...
- [Luogu2973][USACO10HOL]赶小猪Driving Out the Piggi…
题目描述 The Cows have constructed a randomized stink bomb for the purpose of driving away the Piggies. ...