Groovy基础与实践.docx
《Groovy基础与实践.docx》由会员分享,可在线阅读,更多相关《Groovy基础与实践.docx(21页珍藏版)》请在冰豆网上搜索。
![Groovy基础与实践.docx](https://file1.bdocx.com/fileroot1/2023-4/19/cd0bc7c8-928b-4c75-a542-21cdb77abf78/cd0bc7c8-928b-4c75-a542-21cdb77abf781.gif)
Groovy基础与实践
GROOVY基础与实践
目录
一、安装grooovy环境2
二、Groovy基本语法3
1、String3
2、数字类型6
3、操作符重载7
4、集合对象8
4、正则表达式10
5、Groovy的控制结构12
7、Groovy静态引入12
8、闭包12
三、高级特性15
1元对象协议15
2DSL21
3脚本特性24
四、Groovy在装修平台中的使用25
1代码流动26
2绑定数据和服务Bean26
3抽象模块实现27
作者:
绍圣
时间:
2010/10/28
一、安装grooovy环境
可以使用压缩包和安装包两种方式来安装groovy。
不管以哪种方式安装groovy环境,请首先确保,本地的JAVA环境已经正确安装。
首先来看使用压缩包的安装:
1、下载并解压包含了groovy整个运行环境和配置的zip包,下载地址为:
http:
//dist.codehaus.org/groovy/distributions/groovy-binary-1.7.5.zip
2、将解压后的目录下的bin目录地址添加到系统环境变量PATH中
3、验证安装是否成功,在命令行输入groovy–version看看是否有具体版本号或者输入groovyConsole看是否有图形界面的groovy控制台显示出来。
另外一种方式就比较简单了,直接下载安装包,安装即可。
⏹Linux的安装包下载地址为:
http:
//dist.groovy.codehaus.org/distributions/rpm/groovy-1.7.1-2.noarch.rpm下载之后直接使用rpm–ivhgroovy-1.7.1-2.noarch.rpm进行安装。
⏹Windows下安装更为简单,安装包下载地址:
http:
//dist.codehaus.org/groovy/distributions/installers/windows/nsis/groovy-1.7.5-installer.exe双击安装完之后,环境变量什么都设置好了,直接使用即可。
二、Groovy基本语法
1、String
在JAVA中,String的操作总是同其它对象一下,任何操作都是要一丝不苟地进行方法调用,Groovy在语法特性上加入了对String的便捷支持。
为了更好的扩展String类(Java中是final型),Groovy定义了GString作为String的支持。
具体来看,Groovy带给String的灵活特性:
1)字符运算
在java的世界中很难想象能偶对字符串进行直接的加减等运算,而Groovy在语法层面上直接支持这样的疯狂操作,比如一下代码
defa="shao"
defb="sheng"
asserta*2=="shaoshao"
asserta+a=="shaoshao"
assert"shaosheng"-a==b
2)字符串模板
Groovy中支持像Velocity一样的字符模板,我们可以多行的方式定义字符串,并且在字符串中使用当前作用域中所能获取的任何变量,比如
defa="shao"
defb="sheng"
defc="""${a}$bisa
javadeveloper!
"""
printlnc
输出:
shaoshengisa
javadeveloper!
3)字符串的分割处理
Java中我们喜欢用subString方法来分割字符串,但是在Groovy中,语法上通过下标运算符支持通过更为灵活的字符串组合,比如以下代码:
defa="shaosheng"
asserta[2,7,8]=="ang"
asserta[0..3]=="shao"
asserta[-1..4]=="gnehs"
asserta[4..8]==a[-5..-1]
在下表运算中,下标为整数,从左往右开始计数,左边第一个字符下标为0,下标为负数,从右往开始计数,右边第一个字符下标为-1。
Groovy的这些特性都是通过在GString中实现操作符重载达到效果的。
4)结合闭包的特性,延迟绑定变量
defname="shaosheng"
defa="${->name}isajavadeveloper!
"
printlna
name="Andy"
printlna
输出:
shaoshengisajavadeveloper!
Andyisajavadeveloper!
5)Groovy还为字符串提供很多有用的扩展方法
padLeft,padRight生成指定的不小于当前字符串长度的新字符串,左右分别以空格补齐,如代码
defa="shaoshengisajavadeveloper!
"
println"####"+a.padRight(40)+"####"
println"####"+a.padLeft(40)+"####"
输出:
####shaoshengisajavadeveloper!
####
####shaoshengisajavadeveloper!
####
Revese方法允许生成一个新的字符串,对当前字符串的字符倒序排列
defa="shaoshengisajavadeveloper!
"
printlna.reverse()
printlna
输出
!
repolevedavajasignehsoahs
shaoshengisajavadeveloper!
2、数字类型
在JAVA中,有基本类型和对象类型之分,后来又提供了基本类型和对象类型之间的自动装箱和拆箱功能,而在Groovy语言世界中,一切都是为对象,包括数字。
在与JAVA的交互过程中,Groovy会自动的装箱和拆箱,以适应JAVA的接口类型。
在GROOVY中小数默认都是BigDecimal类型,看一下代码
defa=1
printlna.class.name
defb=1.1
printlnb.class.name
输出
java.lang.Integer
java.math.BigDecimal
Groovy中一些运算符也和JAVA中的实际效果略有差别,比如/在JAVA中式整除但是在Groovy中运算结果却可以是小数,代码如下
assert0.5==1/2
另外Groovy还提供乘方预算符**,代码如下
assert64==4**3
3、操作符重载
Groovy提供运算符重载的语言支持,类似于C++,在定义一种类型的时候,只要定义哪些基于名字约定的操作符方法名酒可以实现操作符重载,具体看代码:
classA{
defname
defplus(Aa){
defc=newA(name:
name+"is"+a.name)
returnc
}
StringtoString(){
returnname
}
}
defa=newA(name:
"shaosheng")
defb=newA(name:
"andy")
defc=a+b
printlncprintlnc.name输出:
shaoshengisandy
4、集合对象
Groovy在语法层面上加强对了集合对象数组和MAP做了支持,并且引入了新的数据结构范围(Range)。
并且提供了很多扩展方法,以下是具体的使用实例:
1)关于数组(底层结构使用的是LinkedList,不同版本可能不同)
assert[1,2,3,4]==(1..4)
assert[1,2,3]+[1]==[1,2,3,1]
assert[1,2,3]<<1==[1,2,3,1]
assert[1,2,3,1]-[1]==[2,3]
assert[1,2,3]*2==[1,2,3,1,2,3]
assert[1,[2,3]].flatten()==[1,2,3]
assert[1,2,3].reverse()==[3,2,1]
assert[1,2,3].disjoint([4,5,6])
assert[1,2,3].intersect([4,3,1])==[3,1]
assert[1,2,3].collect{it+3}==[4,5,6]
assert[1,2,3,1].unique().size()==3
assert[1,2,3,1].count
(1)==2
assert[1,2,3,4].min()==1
assert[1,2,3,4].max()==4
assert[1,2,3,4].sum()==10
assert[4,2,1,3].sort()==[1,2,3,4]
assert[4,2,1,3].findAll{it%2==0}==[4,2]
2)关于MAP的使用
defmap=[a:
1,'b':
2]
printlnmap//["a":
1,"b":
2]
printlnmap.a//1
printlnmap['a']//1
printlnmap.keySet()//["a","b"]
3)关于Range的使用
定义1到10范围的所有值:
def=1..10
定义1到9范围的所有值:
def=1..<10
但是这样定义1>..10和1<..10两种定义方式都不行。
不仅仅整数,Groovy还支持使用字符来定义Range,比如defa='a'..'b或者defa='d'..'a'。
也可以使用小数定义Range,比如defa=1.2..9.1,实际的数据列表却是
1.2
2.2
3.2
4.2
5.2
6.2
7.2
8.2
看出他是以初始值依次递加1,知道超过最大范围值。
另外Groovy提供了一些常用的方法
range.contains(5)
range.size()
range.from
range.to
Range同for循环一起使用,能够使得代码非常方便易读。
4、正则表达式
在语法层面上,Groovy提供了对正则表达式的支持,提供了对应的操作符专门用于操作正则表达式,不像JAVA那样进行正则表达式的匹配,需要创建一堆的对象,进行多次函数调用,Groovy可以使用很少的代码达到JAVA的效果,大大提高开发效率。
Groovy提供了三个运算符用于支持正则表达式:
~,=~,==~:
运算符~:
将字符串解释成JAVA中的Pattern
运算符=~:
从字符串左边开始匹配正则表达式,返回Java正则包中的Matcher对象
运算符==~:
用于完全匹配字符串和正则表达式,返回boolean对象
另外,为了方便组装正则表达式字符串,Groovy提供了斜杠语法,具体来代码:
defp=(~"[0-9]+")
printlnp.class
println"shao.sheng.shao"=~"shao"
println"shao.sheng"==~"shao.sheng"
println"10.34"==~/[0-9]+\.[0-9]+/
输出:
classjava.util.regex.Pattern
java.util.regex.Matcher[pattern=shaoregion=0,15lastmatch=]
true
true
正则表达式用于字符串集合
assert["shao","sheng"]==["shao","sheng","andy"].grep(~/sh[a-z]+/)
或者
assert["shao","sheng"]==["shao","sheng","andy"].findAll{it=~/sh[a-z]+/}
正表达式用于字符串处理
第一次匹配做替换assert"andyaosheng"=="shaosheng".replaceFirst(/sh/,"andy")
5、Groovy的控制结构
暂略
7、Groovy静态引入
与JAVA相同,Groovy也是提供静态引入特性,但是他比JAVA做得更贴心,不仅能够引入,而且能够赋予别名,比如:
importstaticjava.lang.System.outasprintOut
printOut.println'shaosheng'
输出:
shaosheng
8、闭包
我个人对闭包的理解是可传递复用的代码块。
Groovy编译器在编译Groovy代码的,出现闭包就会将闭包单独编译成为独立的Class。
并且在闭包定义的代码处实例化这个特殊类。
闭包与其被定义所在代码区域有着密切的联系。
闭包可以赋值给变量,可以在方法之间传递,可以组合在复杂数据结构中。
闭包的基本结构如下:
{参数列表–>代码块},如果只有一个参数,参数列表和标识符->都可以省略,演变成{代码块},唯一的参数可以使用it来索引(但是有些地方,即便是只有一个参数或者没有参数,也不能省略标识符->,比如字符模板中)。
1)最基本的定义和使用一个闭包,代码如下:
defcount={a,b->a+b}
printlncount(1,2)//或者以函数调用的方式来使用闭包count.call(1,2)
之前说过,闭包跟定义它的环境息息相关,闭包中可以直接访问外部的变量,前提是变量的定义要在必须要在闭包定义之前,如下面的代码
defname="shaosheng"
defcount={a,b->a+b+name}
printlncount(1,2)
闭包定义之后,默认的外部对象便是定义闭包的对象,除非主动改变,在闭包的传递过程中都不会改变。
2)使用闭包来实现接口
在与java的互操作的过程中通常需要实现java的接口,采用Groovy的类定义可以达到这样的效果,但是更Groovy一点的方式是使用闭包来实现匿名接口,甚至于达到JAVA中匿名内部类的效果(Groovy不支持内部类),代码如下:
针对只有一个方法的接口,实现
interfaceTestInterface{
defshow()
}
deftest={println"""I'mshaosheng"""}asTestInterface
test.show()
针对包含多个方法的接口实现,代码如下:
interfaceTestInterface{
defask()
defanswer()
}
deftest=[
ask:
{println"Whoareyou?
"},
answer:
{println"I'mshaosheng!
"}
]asTestInterface
test.ask()
test.answer()
3)闭包的常用场景
操作和解读集合数据
(1..10).each{printlnit}
3.times{printlnit**2}
defname=[real:
"andy",nick:
"shaosheng"]
name.each{key,map->printlnkey+""+map}
读文件
newFile(/D:
\data.txt/).eachLine{printlnit}
4)将方法转成闭包
classTest{
defname
defshow(other){
println"${other},mynameis${name}"
}
}
deftest=newTest(name:
'shaosheng');
defs=test.&show
s('andy')
三、高级特性
1元对象协议
在groovy中不管是类还是对象都会有一个元类型(MetaClass),groovy神奇的动态特性就是通过元类型来实现的。
通过元类型,可以在运行时对类和具体对象添加删除方法,属性,这两有两个层次,一个是类层次,一个是对象层次,对类的元对像进行方法或者属性的添加和删除,会影响到该类的所有对象,对某个对象进行方法或者属性的添加或者删除不会影响到类本身和其它对象,有以下代码:
方法和属性的添加
String.metaClass.hello={println"helloworld!
"}
defstr1="abc"
defstr2="def"
str2.metaClass.flag="hasaflag"
str1.hello()
str2.hello()
printlnstr2.flag
以上代码运行都没有问题,能够按照我们预期输出数据
helloworld!
helloworld!
hasaflag
但是当我们调用printlnstr2.flag,就会抛出找不到方法的异常。
运行期判定Groovy对象的方法是否或者属性是否存在
hasProperty和respondsTo用于判定具体对象方法是否存在
respondsTo和hasMetaMethod用于判定对象所属类型的属性和方法是否存在
classTest{
defname
defshow(){
println"mynameis${name}"
}
}
deftest=newTest()
asserttest.metaClass.hasProperty(test,"name")
asserttest.metaClass.respondsTo(test,"show")
asserttest.metaClass.hasMetaProperty("name")
asserttest.metaClass.hasMetaMethod("show")
1)Groovy方法和属性的分派
Groovy中有三个特殊命名的方法invokeMethod,methodMissing,propertyMissing,赋予了特殊职能。
●invokeMethod:
如果一个类实现了该方法,当调用了该类的对象中不存在的方法的时候,该方法会被执行,如果希望该类的所有方法调用都分派到该方法上,那么这个类就必须实现一个接口GroovyInterceptable。
●methodMissing:
如果一个类实现了该方法,当调用了该类的对象中不存在的方法的时候,该方法会被执行。
如果一个类同时实现了invokeMethod和methodMissing方法,在找不到对应方法的时候优先将调用分派到methodMissing上。
●propertyMissing:
如果一个类实现了改方法,当读取该类的某个属性时,会调用该方法。
具体看一下代码:
classA{
defname
defshow(){
return"调用了方法show"
}
definvokeMethod(Stringname,Objectargs){
return"调用方法${name}被分派到invokeMethod"
}
defpropertyMissing(p){
return"没有该属性:
${p}"
}
}
defa=newA(name:
"shaosheng")
printlna.show()
printlna.aMissingMethod()
printlna.aMissingProperty
输出为:
调用了方法show
调用方法aMissingMethod被分派到invokeMethod
没有该属性:
aMissingProperty
当定义了missingMethod方法之后,代码如下
classA{
defname
defshow(){
return"调用了方法show"
}
definvokeMethod(Stringname,Objectargs){
return"调用方法${name}被分派到invokeMethod"
}
defmethodMissing(Stringname,Objectargs){
return"调用方法${name}被分派到methodMissing"
}
defpropertyMissing(p){
return"没有该属性:
${p}"
}
}
defa=newA(name:
"shaosheng")
printlna.show()
printlna.aMissingMethod()
printlna.aMissingProperty
输出:
调用了方法show
调用方法aMissingMethod被分派到methodMissing
没有该属性:
aMissingProperty
当实现了接口GroovyInterceptable之后,代码如下
classAimplementsGroovyInterceptable{
defname
defshow(){
return"调用了方法show"
}
definvokeMethod(Stringname,Objectargs){
return"调用方法${name}被分派到invokeMethod"
}
defmethodMissing(Stringname,Objectargs){
return"调用方法${name}被分派到methodMissing"
}
defpropertyMissing(p){
return"没有该属性:
${p}"
}
}
defa=newA(name:
"shaosheng")
printlna.show()
printlna.aMissingMethod()
printlna.aMissingProperty
输出
调用方法show被分派到invokeMethod
调用方法aMissingMethod被分派到invokeMethod
没有该属性:
aMissingProperty
2DSL
Groovy支持MOP,支持闭包特性,可以省略方法调用时候的小括号,使得它很容易实现DSL。
在很多DSL的实现中,都是充分利用了invokeMethod方法的调用分派特性。
具体来看一个网上比较常见的例子,通过Groovy编写一个DSL,构建XML字符串。
我们的目的是直接书写这样的代码就能够很容易的转换输出成为xml代码方式:
xml.html{
head{
title