目录
#乘方
assert 2 ** 3 == 8
#非运算
assert (!true) == false
assert (!'foo') == false
assert (!'') == true
#三元表达式
result = (string!=null && string.length()>0) ? 'Found' : 'Not found'
result = string ? 'Found' : 'Not found'
#艾维斯运算符
displayName = user.name ? user.name : 'Anonymous'
#进一步简写为:
displayName = user.name ?: 'Anonymous'
避免抛出NullPointerException
这个异常。
def person = Person.find { it.id == 123 }
def name = person?.name
assert name == null
接字段访问 .@
可以跳过 getXXX
方法,直接获得字段的值
assert user.@name == 'Bob'
方法指针 (.&)
操作符可以获取一个方法指针,后面再调用这个指针
def str = 'example of method reference'
def fun = str.&toUpperCase
def upper = fun()
方法指针获得的值是一个groovy.lang.Closure
类型,因此可以用到任何需要闭包的地方,非常适合策略模式
def transform(List elements, Closure action) {
def result = []
elements.each {
result << action(it)
}
result
}
String describe(Person p) {
"$p.name is $p.age"
}
def action = this.&describe
def list = [
new Person(name: 'Bob', age: 42),
new Person(name: 'Julia', age: 35)]
assert transform(list, action) == ['Bob is 42', 'Julia is 35']
Groovy 允许重载多个同名方法,如果方法指针指向重载同名方法,则根据参数类型来判断调用哪个方法
def doSomething(String str) { str.toUpperCase() }
def doSomething(Integer x) { 2*x }
def reference = this.&doSomething
assert reference('foo') == 'FOO'
assert reference(123) == 246
模式运算符、匹配对象操作符、直接匹配操作符
略。
扩展操作符的本质是迭代调用并生成列表,因此任何实现了 Iterable 接口的对象都可以使用扩展操作符
class Component {
Long id
String name
}
class CompositeObject implements Iterable<Component> {
def components = [
new Component(id: 1, name: 'Foo'),
new Component(id: 2, name: 'Bar')]
@Override
Iterator<Component> iterator() {
components.iterator()
}
}
def composite = new CompositeObject()
assert composite*.id == [1,2]
assert composite*.name == ['Foo','Bar']
1.解包方法参数
下面这个方法需要三个参数
int function(int x, int y, int z) {
x*y+z
}
下面这个列表有三个元素
def args = [4,5,6]
将列表解包为三个参数传给方法
assert function(*args) == 26
位置可以随意
args = [4]
assert function(*args,5,6) == 26
2.解包列表元素
def items = [4,5]
def list = [1,2,3,*items,6]
assert list == [1,2,3,4,5,6]
3.解包键值对
def m1 = [c:3, d:4]
def map = [a:1, b:2, *:m1]
assert map == [a:1, b:2, c:3, d:4]
如果出现重复的的键,后面的值将替换前面的值
def m1 = [c:3, d:4]
def map = [a:1, b:2, *:m1, d: 8]
assert map == [a:1, b:2, c:3, d:8]
范围操作符 (..)
创建一个 groovy.lang.Range
对象,这个类型同时实现了 List
接口
def range = 0..5
assert (0..5).collect() == [0, 1, 2, 3, 4, 5]
assert (0..<5).collect() == [0, 1, 2, 3, 4]
assert (0..5) instanceof List
assert (0..5).size() == 6
Range
对象是轻量级的,仅仅存储了上下边界,因此要创建 Range
还必须实现 Comparable
接口中的 next()
方法和 previous()
方法。因为字符对象实现了这两个方法,因此可以向下面这样用
assert('a'..'d').collect()==['a','b','c','d']
比较操作符 (<=>)
其实就是 compareTo
方法
assert (1 <=> 1) == 0
assert (1 <=> 2) == -1
assert (2 <=> 1) == 1
assert ('a' <=> 'z') == -1
索引操作符本质上是调用 getAt
和 putAt
方法,可以切片获取或者切片赋值
def list = [0,1,2,3,4]
assert list[2] == 2
list[2] = 4
assert list[0..2] == [0,1,4]
list[0..2] = [6,6,6]
assert list == [6,6,6,3,4]
可以重写 getAt/putAt
方法,实现一些自定义的行为
class User {
Long id
String name
def getAt(int i) {
switch (i) {
case 0: return id
case 1: return name
}
throw new IllegalArgumentException("No such element $i")
}
void putAt(int i, def value) {
switch (i) {
case 0: id = value; return
case 1: name = value; return
}
throw new IllegalArgumentException("No such element $i")
}
}
def user = new User(id: 1, name: 'Alex')
assert user[0] == 1
assert user[1] == 'Alex'
user[1] = 'Bob'
assert user.name == 'Bob'
成员操作符 (in)
相当于调用了列表的 contains
方法或者 isCase
方法
def list = ['Grace','Rob','Emmy']
assert ('Emmy' in list)
calling list.contains('Emmy')
和 list.isCase('Emmy')
是同样的功能
==
和is操作符在 Groovy 中, ==
仅仅检测值是否相同,如果想检测是否是同一个对象,使用 is
操作符
def list1 = ['Groovy 1.8','Groovy 2.0','Groovy 2.3']
def list2 = ['Groovy 1.8','Groovy 2.0','Groovy 2.3']
assert list1 == list2
assert !list1.is(list2)
转型操作符 (as) 可以转换一些不兼容变量的类型,例如下面的转换会抛出异常
Integer x = 123
String s = (String) x
用转型操作符可以正确转换
Integer x = 123
String s = x as String
转型的本质实际上是调用了对象的 asType 方法,可以重写这个方法实现一些自定义的行为
class Identifiable {
String name
}
class User {
Long id
String name
def asType(Class target) {
if (target==Identifiable) {
return new Identifiable(name: name)
}
throw new ClassCastException("User cannot be coerced into $target")
}
}
def u = new User(name: 'Xavier')
def p = u as Identifiable
assert p instanceof Identifiable
assert !(p instanceof User)
钻石操作符 (<>)
仅仅是为了兼容 Java 7 中的泛型,目前在 Groovy 中还没有什么用处。
List<String> strings = new LinkedList<>()
调用操作符 ()
隐式调用 call
方法。可以重写 call
实现一些自定义的行为,然后用调用操作符调用
class MyCallable {
int call(int x) {
2*x
}
}
def mc = new MyCallable()
assert mc.call(2) == 4
assert mc(2) == 4
略。参见:http://groovy-lang.org/operators.html#Operator%20precedence
类似于c++的操作符重载,Groovy 中的大部分操作符都可以重新定义,例如:
class Bucket {
int size
Bucket(int size) { this.size = size }
Bucket plus(Bucket other) {
return new Bucket(this.size + other.size)
}
}
#方法 plus() 重载了 + 操作符
def b1 = new Bucket(4)
def b2 = new Bucket(11)
assert (b1 + b2).size == 15
下表是各个操作符的函数名称:
操作符 | 方法 | 操作符 | 方法 |
---|---|---|---|
+ | a.plus(b) | a[b] | a.getAt(b) |
- | a.minus(b) | a[b] = c | a.putAt(b, c) |
* | a.multiply(b) | a in b | b.isCase(a) |
/ | a.div(b) | << | a.leftShift(b) |
% | a.mod(b) | >> | a.rightShift(b) |
** | a.power(b) | >>> | a.rightShiftUnsigned(b) |
| a.or(b) |
| a.next() |
& | a.and(b) | -- | a.previous() |
^ | a.xor(b) | +a | a.positive() |
as | a.asType(b) | -a | a.negative() |
a() | a.call() | ~a | a.bitwiseNegative() |