【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 ...
随机推荐
- bat脚本自动安装Jmeter&Jdk
一句话能解决的事情,绝对不要写一篇文章:一篇文章能解决的事情,绝对不要使用各种工具:一个工具能解决的事情,绝对不要跑东跑西…… 文章主要介绍脚本如何下载.安装.配置Jmeter&Jdk. 不多 ...
- 给老师安排课表JAVA项目及登录窗口的实现
实现一个安排课表的Java实验. 有以下几点要求: ①用所给的教师姓名进行课表安排 ②用所给的地点进行课表安排 ③不得有重复的课程名称出现 ④将信息写入到文件里 ⑤用窗口来进行实现 package c ...
- python入门之jieba库的使用
对于一段英文,如果希望提取其中的的单词,只需要使用字符串处理的split()方法即可,例如“China is a great country”. 然而对于中文文本,中文单词之间缺少分隔符,这是中文 ...
- CentOS 7.7版本中NAT上网问题
一.NAT(地址转换模式)概念 如果你的网络ip资源紧缺,但是你又希望你的虚拟机能够联网,这时候NAT模式是最好的选择.NAT模式借助虚拟NAT设备和虚拟DHCP服务器,使得虚拟机可以联网. 二.具体 ...
- 二、docker 镜像容器常用操作(让我们用docker 溜得飞起)
前言 上篇讲了我们如何安装docker,现在该我们一展拳脚的时候了.接下来让我们一起学习一下docker常见的操作,让我们能够会使用 docker. 基本概念 在讲使用之前,还是先将一下docker ...
- Cobalt Strike之CHM、LNK、HTA钓鱼
CHM钓鱼 CHM介绍 CHM(Compiled Help Manual)即“已编译的帮助文件”.它是微软新一代的帮助文件格式,利用HTML作源文,把帮助内容以类似数据库的形式编译储存.利用CHM钓鱼 ...
- Python开发【第五篇】字符串
字符串 作用:用来记录文字信息 例子: 空字符串 '' #单引号空字符串 "" #双引号空字符串 ''' ''' #三单引号空字符串 """ &quo ...
- Tomcat源码分析三:Tomcat启动加载过程(一)的源码解析
Tomcat启动加载过程(一)的源码解析 今天,我将分享用源码的方式讲解Tomcat启动的加载过程,关于Tomcat的架构请参阅<Tomcat源码分析二:先看看Tomcat的整体架构>一文 ...
- python2与3实际中遇到的区别
1.type(1/2) python2是向下取整,0,为int:python3是正常除法,0.5,为float 2.
- {每日一题}:四种方法实现打印feibo斐波那契数列
刚开始学Python的时候,记得经常遇到打印斐波那契数列了,今天玩玩使用四种办法打印出斐波那契数列 方法一:使用普通函数 def feibo(n): """ 打印斐波那契 ...