Groovy详解
一、安装:
两种安装方式:
直接官网下载,然后在配置中(.bash_profile的PATH中)加上groovy的路径
直接在命令行brew install groovy,然后在配置中(.bash_profile的PATH中)加上groovy的路径(路径会在install 结束后提示)
验证安装成功:
命令行执行groovy -v,如果没有报错,且可以看到groovy版本,则成功。
注意安装之后要source .bash_profile或者重启terminal以让配置生效。(使用zsh用 source .zshrc)
二、groovy的运行
.groovy可以直接运行,也可以先编译为.class,再以java字节码运行(java和groovy两者完全兼容,因为他们都可以编译为.class,groovy可以看做java的简化版,代价是系统帮你做了很多操作,也就会体积更大,有时候可能会牺牲一些性能)
java与groovy运行对比:
java:
.java程序必须先javac编译为.class,然后再java运行
groovy:
(1)、groovy可以直接像脚本一样在命令行运行,如:groovy -e "println 'Hello World'"
(2)、也可以写一个.groovy文件,文件中直接写一句println “Hello World”就可以了,系统会自动为你加上缺省的所有代码,包括public class…,main…,以及缺省的包等。最后直接运行 groovy xxx.groovy
(3)、还可以写一个.groovy文件,然后groovyc xxx.groovy编译为.class文件,然后java xxx.class运行.class文件。但是实际上直接这样是会报错误: 找不到或无法加载主类,这是因为我们写的.groovy,会import一些groovy的包,通过反编译,可以看到class会extends Script类,这个时候我们需要加上这些东西的classpath,如:java -cp /usr/local/Cellar/groovy/2.4.7/libexec/embeddable/groovy-all-2.4.7.jar:. MyFirstExample(其中,:是mac中的分隔符,在windows中是;)
其中,(1)、(2)都是直接运行groovy脚本,而(3)是将groovy先编译为.class字节码文件,然后再在jvm上执行
三、groovy特征
1、groovy可以与java在代码上互换
简洁的groovy代码:
class HelloWorld {
static main(args) {
println "Hello World"
}
}
一行代码结束时不需要写;
默认为public,可以不写访问修饰符
static方法可以不定义返回类型,默认为def
方法调用的时候也可以简写
用java的格式也可以写:
publicclassHelloWorld {
publicstaticvoidmain(String[] args) {
System.out.println("Hello World")
}
}
2、groovy变量定义
def:
申明变量的时候,可以直接用def
实际上,通过反编译groovy编译之后的.class文件,发现def在编译为.class文件后,就是一个Object
一切皆对象:
groovy没有基础类型,定义的int等,实际对应的是其包装类型Integer
多个变量定义:
定义变量可以多个一起定义,如:
def (a,b) = [3, “a”]
也可以通过方法返回多个值来赋值(实际上是返回一个List),如:
def(c,d) = repeat("repeat",3)
3、groovy的循环
范围表示方式:
可以写成0..4的格式,表示[0,4]
还可以写成0..<4,表示[0,4)
4、groovy的方法
static方法可以在方法声明中没有返回值,默认会加上def
如果没有return,则以最后一行为返回值,如果最后一行没有含义,返回null
参数列表可以不指定类型,默认为def
参数可以设置默认值,设置了默认值的参数,可以不传,如:
staticrepeat(val, repeat =5, a){
for(iin0..repeat){
printlnval
}
printlna
}
调用repeat("repeat",3),这个时候,3对应的参数是a,repeat为默认值5
也可以repeat("repeat”,3,4),这个时候,3对应的是repeat,repeat为3,a为4
5、groovy的集合
定义:
可以
def range = 0..4
也可以
def coll = ["Groovy", "Java", "Ruby"]
添加项:
coll.add("Python")
coll << "Smalltalk"
coll[5] = "Perl"
第一、第二种方式,都会在末尾加一个值
第三种方式,如果已有该下标的值,则覆盖;如果没有,则将集合扩大到能容纳该下标,然后加上该值,中间缺省位置默认值为null,如:
def coll = ["Groovy", "Java", "Ruby"]
coll[5] = "Perl"
此时coll的值为["Groovy", "Java", “Ruby”, null, null, “Perl"]
检索:
通过下标
增加或去掉集合:
可以通过+/-来对集合进行加减操作,如:
defnumbers= [0, 1, 2, 3, 4]
printlnnumbers+ 6
printlnnumbers- [2,4]
此时输出的是:
[0, 1, 2, 3, 4, 6]
[0, 1, 3]
由此可见+/-操作是创建了一个新的实例
其它魔法方法:
join():
defnumbers= [1,2,3,4,3,2,1]
printlnnumbers.join(",")
输出为:1,2,3,4,3,2,1
count():
defnumbers= [1,2,3,4,3,2,1]
printlnnumbers.count(3)
输出为:2
分布操作符(spread operator):
可以对集合每个元素都执行操作,省去迭代的操作:
coll= ["Groovy","Java","Ruby"]
println coll*.toUpperCase()
println coll
输出为:
[GROOVY, JAVA, RUBY]
[Groovy, Java, Ruby]
注意toUpperCase()也是新创建一个实例
6、groovy的映射
定义:
除了常规方式,还可以这样定义映射:
defhash= [name:"Andy","VPN-#":45]
修改与添加:
修改与添加的方式,可以直接通过.号或者[]来,如:
hash.”name” = “Mike"
也可以省略””(如果key中有-等无法识别的,不能省略),如:
hash.name= “Mike"
还可以:
hash[“name”] = “Mike”
[]中的双引号不能省略
示例:
defhash = [name:"Andy","VPN-#":45]
printlnhash
hash.name ="Mike"
hash["VPN-#"]=46
hash.dob ="17/08/08"
printlnhash
输出为:
[name:Andy, VPN-#:45]
[name:Mike, VPN-#:46, dob:17/08/08]
四、闭包
闭包单独拿出来说,是因为groovy的闭包,是一个很重要的新概念。通过反编译groovy生成的.class文件,可以看到闭包实际上是一个class,继承自Closure类
1、创建闭包:
形如以大括号括起来的代码块,参数放在大括号开头,以→结束(其实应以[]括起来,但可省略):
defa = { vala1,vala2 ->
vala1 + vala2
}
printlna(1,"a")
输出为:1a
2、特殊情况参数简化:
如果只有一个参数,可以不定义,默认为it;it可以被手动定义,不建议在闭包中定义参数名为it,避免歧义
如果参数最后也是闭包,可以不写在()内,可以在后面以{}来定义,如:
defa = { vala1,vala2 ->
vala1 + vala2()
}
printlna(1){"a"}
如果最后有多个闭包,则{}{}连起来
如果只有闭包参数,前面的()可以省略,方法参数中是闭包的情况也可以省略()
闭包会把map键值对组装到一起作为第一个参数,如:
defb = {valb1,valb2,valb3->
valb1.x+valb1.y+valb1.z+valb2+valb3
}
printlnb(x:3,4,y:5,6,z:7)
输出为25
可以像方法一样,参数设置默认取值,调用方法的时候就可以忽略该参数
可以在参数列表最后放一个Object[],来获取任意多个参数
3、闭包提供的特殊方法:
getMaximumNumberOfParameters()方法可以用来查闭包参数个数
curry()方法可以重载原闭包,并将一些参数赋值,如:
defd = {vald1,vald2,vald3->
vald1+vald2+vald3
}
defe=d.curry(1)
printlne(2,3)
输出为6
4、闭包可以迭代
5、闭包的委托策略:
三个关键字:
this表示定义闭包的外围类。
owner表示定义闭包的直接外围对象,可以是类或者闭包。
delegate表示一个用于处理方法调用和属性处理的第三方类。
this关键字用来获取闭包的外围类
owner与this不同的是,它如果在另一个闭包中定义,则指向定义它的闭包(实际上,闭包也是一个类,可以理解this忽略了闭包)
delegate默认与owner一样,但可以手动指定,指定之后,闭包中没有拥有者的参数会从delegate中获取,如:
deff = {
valf1+valf2+valf3
}
deffv = [valf1:1,valf2:2,valf3:3]
f.delegate=fv
printlnf()
输出为:6
6、delegate策略:
Closure.OWNER_FIRST这是默认的策略,优先从owner中寻找属性或方法,找不到再从delegete中寻找。上面的例子就是因为在owner中没有找到name,接着在delegate中找到了name属性。
Closure.DELEGATE_FIRST与OWNER_FIRST相反。
Closure.OWNER_ONLY只在owner中寻找。
Closure.DELEGATE_ONLY只在delegate中寻找。
Closure.TO_SELF在闭包自身中寻找。
可以使用闭包的resolveStrategy属性来设置delegate策略
实际上,闭包始终会在定义闭包的方法中找有没有局部定义的变量,如果没有,才会走delegate策略
五、参考资料
groovy官方文档:http://www.groovy-lang.org/closures.html
闭包语法总结:http://attis-wong-163-com.iteye.com/blog/1239819
闭包文档翻译:http://www.cnblogs.com/zqlxtt/p/5741297.html
IBM文档(整体讲的不错,但个人觉得闭包讲的不太仔细):https://www.ibm.com/developerworks/cn/education/java/j-groovy/j-groovy.html