Groovy与Java的区别
1. 下载安装Groovy,并配置到系统环境变量.(http://groovy.codehaus.org)
2. 在命令行中输入groovy -v可以查看是否安装成功,并查看到对应版本号.
Groovy也给用户提供了GUI界面的工具. 在"运行"中输入"groovyConsole"便会启动groovy控制台,可以在里面编写简单的groovy程序.
3. 基本类型
在Groovy中一切都是对象. 这点不同于Java!
3.1 字符串
单引号"'"、 双引号"""、斜框"/"都可以表示字符串
单引号"'"表示静态的字符串;双引号"""表示的动态字符;"/"用户定义转义字符串.
def str1 = 'hello' def str2 = "$str1 world" //字符串中包含表达式的运算,所以是动态的 assert str2 == 'hello world' def str3 = /\d\r\n\a\b/ assert str3 == '\\d\\r\\n\\a\\b'
assert是Groovy的一个常用的方法:断言. 含义是若断言的内容为假,则报异常退出程序.
字符串常见的运算符操作:
assert str1 * 2 == 'hellhello' //字符串乘以数字 assert str2 - str1 == ' world' //字符串减法,会删除str2中左边第一个匹配的str1 assert str2[0..3] == 'hell' assert str2[1,3] == 'ell' assert str2[-3..-1] == 'rld'
a..b的结构在Groovy中叫做区间(Range).
assert str2.toList() == ["h","e","l","l","o"," ","w","o","r","l","d"] assert str1.reverse() == "olleh" assert str2.size() == 20
3.2 数字
Groovy中的数据是对象,因而可以在数字上调用方法:
def x = 3 def y = 4 assert x + y == 7 assert x.plus(y) == 7 assert x instanceof Integer def a =2 / 3 // 0.6666666667 assert a instanceof BigDecimal a = 2.intdiv(3) assert a instanceof Integer def b = a.setScale(3, BigDecimal.ROUND_HALF_UP) assert b == 0.667
3.3 Groovy的类
Groovy的类默认情况下(无需用户实现)可以使用一个Map作为构造函数的参数,对象的属性会被Map的同名key所对应的值初始化.
class A { String p1 String p2 } def a = new A(p1:"string1", p2:"string2") assert a.p1 == "string1" && a.p2 == "string2"
Groovy中没有定义访问限定符(如puglic ,private ,protected).
Java类中默认的访问域是package, 但在Groovy中,默认是属性域.
Groovy提供的去处符:"?". 例如,当要访问a.b.c的时候,难免要做些判断保证a和不为null,否则抛异常.平常写法代码如下
if(a!=null) { if(a.b !=null) return a.b.c else return null } else { return null }
Groovy中的写法
a?.b?.c
3.4 Groovy的控制结构
Groovy的if可接受的类型不仅仅是boolean,还可以是数字,字符串,对象,集合. 传boolean或Boolean时处理逻辑跟Java相同; 传数字时,非0为真,0为假; 传字符串时,空字符串""为假,其他为真; 传集合时, 元素个数等于0为假, 大于0为真; 传Object时,null为假, 否则为真! 例如:
if(true && Boolean.TRUE) assert true else assert false if(1) assert true else assert false if("") assert true else assert false if([]) assert true else assert false def a = null if(a) assert true else assert false
Groovy的循环有两种: 一种Java风格; 另外一种集合遍历风格
//传统风格 for(int i=0; i<=10; i++) println i //集合遍历风格 for(x in 0..10) println x for(x in [1,3,5]) println x
4. 集合类型
Groovy常用3种集合类型:列表List, 映射Map 和 区间 Range
4.1 列表
列表本质就是java.util.List. 只是简化了操作. 初始化时可以直接初始数据. def list1 = [1,2,3]
List 支持大量的运算符和方法:
list1 = list1 * 2 assert list1 == [1,2,3,1,2,3] assert list1.unique() == [1,2,3] list1 = [1,2,3,1,2,3] assert list1.unque() == (list1 as Set) as List // 将List先转为Set, (可消除重复值), 再转回List,以进行比较. assert list1.size() == 6 assert list1.reverse() == [3,2,1,3,2,1] assert [1,2,3,4] + [5] == [1,2,3,4,5] assert [1,2,3,4] << 5 == [1,2,3,4,5] assert [1,2,3,4] + 5 == [1,2,3,4,5] assert [1,2,3,4,1] - [1] == [2,3,4] assert [1,2,3,4,1] - 1 == [2,3,4] assert [1,2,3,[4,5]].flatten() == [1,2,3,4,5] //展开List中的List assert [1,2,3,4].max() == 4 assert [1,2,3,4].min() == 1 assert [1,2,3,4,1].count(1) == 2 //统计1的个数 assert [1,2,3,4].sum() == 10 //求和 assert [1,2,3,4].sort() == [1,2,3,4] assert ! [1,2,3].disjoint([3,4,5,6]) //存在交集 assert [1,2,3].disjoint([4,5,6]) //不存在交集 assert [1,2,3,4].intersect([5,4,3,1]) == [4,3] //求交集
List有一个非常有用的运算符"*", 它的含义是依次对List每个元素调用"*"后面方法:
def list2 = [[1,1],[2,2],[3,3]] list2*.unique() assert list2 == [[1],[2],[3]]
4.2 映射
Groovy中映射的本质就是java.util.Map; 创建Map,用key:value的形式成对出现,初始化时的key默认会被当作字符串处理,如:
def map [key1: "value1"] assert map == ["key1": "value1"] assert map.key1 == "value1" //用".key"去访问map的成员 assert map["key1"] == "value1" //用"[key]"去访问map的成员 assert map.keySet() == ["key1"]
如果key1是个变量的话, 如下代码可解释:
def key "key123" def map1 = [key: "value"] assert map == ["key":"value"] assert map1.key == 'value' assert map1[key] == null def map2 = [(key): "value"] assert map2 == ["key123":"value"]
在初始化Map时,如果想用某一变量的值作为key,需要用括号将该变量括起来.
初始化过的Map添加和删除key都非常的Easy.. 如:
map1["newKey"] = "newValue" assert map1 == ["key":"value", "newKey":"newValue"] map1.remove("key") assert map1.key == null
4.3 区间
区间是Groovy特有的数据结构. 有两种形式:一种为闭区间"起始..结束"; 另一种为左闭右开区间"起始..结束". 如下代码:
def range1 = 1..5 def range2 = 1..<5 assert range1.contains(5) assert !range2.contains(5) assert range1.size() == 5 assert range2.size() == 4
事实上,区间使用的数据类型并不局限于数字,字符串,日期等一切实现了next()和previous()方法的类型都可以定义为区间
def today = new Date() def yesterday = today -1 assert (yesterday.. today).size() == 2 assert ('a'..'c').contains('b') assert 'b' in ('a'..'c')
区间常见的用法是用于循环和switch语句,代码如:
//区间用于循环 def log = '' for(i in 1..5) log += i assert log == '12345' //区间用于switch def score = 36 switch(score) { case 0..<60 : println '不及格' break case 70..<85 : println '良好' break case 85..<100 : println '优秀' break case 100 : println '完美' default : throw new IllegalArgumentException() }
输出: 不及格
前置"*"运算符可以把区间展开, 用于构造List,例如:
assert [* range1] == [1,2,3,4,5]
5. Groovy的闭包
闭包(Closure)是Java不具备的语法结构. 闭包就是一个代码块, 用"{}"包起来.此时,程序代码也就成了数据,可以被一个变量所引用. 闭包最典型的应用是实现回调函数(callback).Groovy的API大量使用闭包,以实现对外开放.闭包的创建过程很简单,例如:
{ 参数 -> 代码... }
参考下面的例子代码,定义了c1和c2两个闭包,并对它们进行调用:
def c1 = { println it } def c2 = { text -> println text } c1.call("content1") //用call方法调用闭包 c2("content2") //直接调用闭包
"->"之前的部分为闭包的参数,如果有多个参数,之间可用逗号分割:"->"之后的部分为闭包内的唾弃代码. 如果省略了"->"和它之前的部分,此时闭包中的代码,可以用名为"it"的变量访问参数.
闭包的返回值和函数的返回值定义方式是一样的:如果有return语句,则返回值是return语句后面的内容;如果没有return 语句,则闭包内的最后一行代码就是它的返回值.
5.1 闭包的代表
每个闭包都有一个代表(delegate)属性,指定了闭包的代理对象(闭包可以直接访问该对象的成员方法和属性),通过delegate可以访问代表对象.默认情况下,delegate与this是相同的,但可以手动修改delegate的值,使闭包访问其他对象的方法和属性,例如:
class Foo { def method() { println 'call method' } def c1 = { Closure c-> assert delegate == this //闭包c1的delegate与this相同 if(c) { println c.delegate.class //修改传入闭包的delegate,使得传入的闭包可以访问Foo的成员 c.delegate = this // L1 c() } } } def foo = new Foo() def c2 = { println delegate.class // L2 method() //L3 } //c2() 此时不能调用c2 //因为L3行引用的method不是全局方法,,所以此时c2中调用method()会报错!
代码运行的输出结果为:
class Script63 class Foo call method
因为闭包c2是全局闭包,所以它的delegate就是全局的Script类,于是第一行会输出ScriptXX. 当执行完L1后,会将foo对象设置成为c2的delegate,于是此后执行L2时会输出class Foo;同理,在设置了c2的delegate为foo后, c2的内部就可以访问foo的成员方法method()了,所以此时不会报错!.
5.2 闭包在GDK中的使用
GDK(Groovy Development Kit)中有大量的API的针对Closure进行操作的.
1. each方法
//Range, List, Map的each方法, 可以进行遍历, 每次取集合的一个元素传入的闭包 def log = "" (1..10).each( { log += it }) assert log == "12345678910" [key1: "value1", key2:"value2"],each({ entry -> println "$entry.key $entry.value" })
输出:
key1 value1 key2 vlaue2 [key1: "value1", key2:"value2"],each({ entry -> println "$key $value" })
输出:
key1 value1 key2 vlaue2
2. finAll方法
//finaAll语句将调用闭包时返回真的元素组成一个新的List assert [1,3,5,7,9].findAll ({ it > 4 } ) == [5,7,9]
3. collect方法
//collect方法将闭包应用于集合的每个元素后,将返回值构造成新的列表 assert [1,3,5,7,9].collect ({ it * it } ) == [1,4,9,16,25]
4. any方法
// any和evey方法用于判断集合是否有符合条件的元素 //any:当集合中至少存在一个元素符合条件时,返回真,否则为假 assert [1,3,5,7,9].any ({ it * it == it + 6 })
5. every方法
//every: 当集合所有元素符合条件时,返回真,否则为假 assert ! [1,3,5,7,9].every ({ it * it == it + 6 })
可应用于闭包的特殊运算符: "引用.&"可以把一个普通的Groovy方法转换成闭包
def hell0(word) { "hello $word" } def c = this.&hello assert c("world") == "hello world"