分类: Java
2009-06-05 14:55:08
1、类
(1)类
l Groovy的类定义和Java类似
Ø 方法可以基于类(static)或实例
Ø 可以为public、protected或private
Ø 支持常用的Java修饰符,如synchronized
l Groovy的不同地方:缺省是public
l Groovy支持JavaBean机制:GroovyBean
l 每个Groovy类都是字节码/JVM级的Java类,任何方法对Java都是有效的,反之亦然
l 你可以指定方法的参数类型和返回类型,这样可以在通常的Java代码中更好的工作
l 你可以用上面的方式来实现接口或重载方法
l 如果省略方法的类型,就会使用缺省的java.lang.Object
(2)脚本
l Groovy支持纯脚本,而不需要声明类,如Foo.groovy包含下面的脚本:
println "Nice cheese Gromit!"
l 运行脚本的过程:
Ø 编译成Foo.class(还会有一些内类),该类扩展groovy.lang.Script
Ø 执行自动生成的main方法
Ø 实例化Foo类
Ø 调用run方法执行脚本内容
l 可以在Java代码中执行脚本,同时还可以传递变量值到脚本中
l Foo.groovy内容修改如下
println "Nice ${cheese} Gromit!"
l 下面是执行脚本的UseFoo类
import groovy.lang.Binding;
import groovy.lang.Script;
public class UseFoo {
public static void main(String[] args) {
Binding binding = new Binding();
binding.setVariable("cheese", "Cheddar");
Script foo = new Foo(binding);
foo.run();
}
}
l UseFoo运行的结果是:Nice Cheddar Gromit!
l 执行脚本的方法是创建Foo类实例,调用其run方法
l Foo类有一个带Binding参数的构造函数,可以通过Binding类的setVariable方法设置值给脚本中的属性变量
l Foo类有一个不带参数的构造函数,在不传递属性变量值时使用
l 在脚本结束后,脚本中创建的任何变量都会在Binding中,以供在Java中访问
l 再将Foo.groovy内容修改如下
println "Nice ${cheese} Gromit!"
cheese = "changed"
l UseFoo类修改为:
import groovy.lang.Binding;
import groovy.lang.Script;
public class UseFoo {
public static void main(String[] args) {
Binding binding = new Binding();
binding.setVariable("cheese", "Cheddar");
Script foo = new Foo(binding);
foo.run();
println binding.getVariable("cheese");
}
}
l UseFoo运行的结果是:
Nice Cheddar Gromit!
changed
(3)脚本中的函数
l 不同于基于Class的Groovy,纯脚本中的函数用def关键字声明
def foo(list, value) {
println "Calling function foo() with param ${value}"
list << value
}
x = []
foo(x, 1)
foo(x, 2)
assert x == [1, 2]
println "Creating list ${x}"
2、闭包
(1)概述
l 闭包是一种传递执行代码块的强大方法。
l 可以把闭包看作Java中的匿名内类,但是只有单一的(匿名)方法。
l 闭包可以被用作循环的一种替代方法
[1, 2, 3, 4].each { println(it) }
l 使用闭包可以使异常处理和关闭资源变得更简单,具体例子请参看Groovy SQL
(2)比较闭包和匿名内类
l 不同于Java匿名内类,Groovy 支持“true closures”:状态可以被传递到闭包外部
l 局部变量在闭包创建时可以被使用和修改;闭包中创建的任何变量可以作为局部变量,对外部可见
l 看下面的例子:
count = 0
last = 0
[1, 2, 3, 4].each { count += it; last = it }
println("the sum is ${count} and the last item was ${last}")
输出结果:the sum is 10 and the last item was 4
(3)闭包是普通对象
l 闭包是在需要时被传递和调用的对象
l 因此可以象下面一样使用:
c = { println("Hello ${it}") }
c.call('James')
c.call('Bob')
l 闭包会被编译成扩展groovy.lang.Closure类的新类
l 下面的省略写法是等价的
c = { println("Hello ${it}") }
c('James')
c('Bob')
(4)闭包的参数
l 闭包可以有任意数目的参数
l 缺省情况,闭包具有单个缺省参数:“it”
l 你可以在闭包声明的开始部分指定参数列表
c = { a, b, c | println("Hello ${a} ${b} ${c}") }
c('cheese', 234, 'gromit')
l 下面是另一个使用两个参数的有用例子,在《Groovy快速入门》已经讲过:
value = [1, 2, 3].inject('counting: ') { str, item | str + item }
assert value == "counting: 123"
value = [1, 2, 3].inject(0) { count, item | count + item }
assert value == 6
3、集合
Groovy支持集合、List、Map和数组
(1)Lists
l 下面是创建List的例子,[]表示空List表达式
list = [5, 6, 7, 8]
assert list.get(2) == 7
assert list instanceof java.util.List
emptyList = []
assert emptyList.size() == 0
emptyList.add(5)
assert emptyList.size() == 1
l 每个List表达式都是java.util.List的实现
(2)范围(Ranges)
l Range允许创建连续值的列表
l 由于Range扩展java.util.List,所以Range可以作为List使用
l 使用..的Range是包括两个边界,使用...的Range只包括开始边界,而不包括结束边界
// an inclusive range
range = 5..8
assert range.size() == 4
assert range.get(2) == 7
assert range instanceof java.util.List
assert range.contains(5)
assert range.contains(8)
// lets use an exclusive range
range = 5...8
assert range.size() == 3
assert range.get(2) == 7
assert range instanceof java.util.List
assert range.contains(5)
assert ! range.contains(8)
l Range可以用于实现java.lang.Comparable的Java对象
// an inclusive range
range = 'a'..'d'
assert range.size() == 4
assert range.get(2) == 'c'
assert range instanceof java.util.List
assert range.contains('a')
assert range.contains('d')
assert ! range.contains('e')
l Range可以用于循环遍历
for (i in 1..10) {
println "Hello ${i}"
}
(3)Maps
l 下面是创建Map的例子,[:]表示空Map表达式
map = ["name":"Gromit", "likes":"cheese", "id":1234]
assert map.get("name") == "Gromit"
assert map.get("id") == 1234
assert map instanceof java.util.Map
emptyMap = [:]
assert emptyMap.size() == 0
emptyMap.put(5, "foo")
assert emptyMap.size() == 1
assert emptyMap.get(5) == "foo"
l Map可以象beans一样操作,但key值(类似属性名)必须为有效的String标识
map = ["name":"Gromit", "likes":"cheese", "id":1234]
assert map.name == "Gromit"
assert map.id == 1234
emptyMap = [:]
assert emptyMap.size() == 0
emptyMap.foo = 5
assert emptyMap.size() == 1
assert emptyMap.foo == 5
(4)使用下标操作符
l 可以在字符串、Lists、Maps...中使用下标进行索引
text = "nice cheese gromit!"
x = text[2]
assert x == "c"
assert x.class == String
sub = text[5..10]
assert sub == 'cheese'
map = ["name":"Gromit", "likes":"cheese", "id":1234]
assert map['name'] == "Gromit"
list = [10, 11, 12]
answer = list[2]
assert answer == 12
list = 100..200
sub = list[1, 3, 20..25, 33]
assert sub == [101, 103, 120, 121, 122, 123, 124, 125, 133]
l 可以使用下标操作符更新项目
list = ["a", "b", "c"]
list[2] = "d"
list[0] = list[1]
list[3] = 5
assert list == ["b", "b", "d", 5]
l 可以使用负索引从最后开始计数
text = "nice cheese gromit!"
x = text[-1]
assert x == "!"
name = text[-7..-2]
assert name == "gromit"
l 也可以使用向后范围(开始索引大于结束索引),返回的结果是反转的
text = "nice cheese gromit!"
name = text[3..1]
assert name == "eci"
4、与Java的不同
(1)通用
l 在Groovy中,==等价于equals(),===意味着标识比较(等同Java中的==)
l 在Java中==意味着原类型的相等和对象的标识比较,如a==b(a和b是指向相同对象的引用)
l 传递闭包给方法或使用GroovyMarkup时,{要和方法的调用在同一行上,如:
[1, 2, 3].each { println it }
l 如果要将{放在独立于方法的一行上,要使用括号()
[1, 2, 3].each (
{ println it }
)
l 下面的写法是无效的,会将闭包解释成独立的闭包,而不会将闭包作为方法的参数传递
[1, 2, 3].each
{
println it
}
(2)应该意识到的事情
l 语句后面的分号是可选的,但在同一行上有多个语句需要用分号分隔
l return关键字可选
l 可以在static方法内使用_this_关键字(何用?)
l 缺省的修饰符是public
l Groovy中的protected等价包的protected和Java的protected
l 补充:方法调用时,括号是可选的
(3)在Java中无效的Groovy新特性
l 闭包
l List和Map的本地语法
l GroovyMarkup和Gpath的支持
l 正则表达式的本地支持
l 多形式的iteration和强大的switch语句
l 动态和静态类型的支持
l 在字符串中嵌入表达式
l 增加了许多新的帮助方法
l 在属性和添加事件侦听方面,简化了编写bean的语法