Groovy 官方文档翻译 - 02 - 操作符
版权声明:本文由“勤劳的悄悄”翻译,并发布在“简书”网,转帖请保留该版权声明。
1.数学运算符
1.1.常用数学运算符
下面是常用的二元运算符:
Operator | Purpose | Remarks |
---|---|---|
+ | 加 | |
- | 减 | |
* | 乘 | |
/ | 除 | 整除使用 intdiv() 方法 |
% | 求余 | |
** | 乘方 |
assert 1 + 2 == 3
assert 4 - 3 == 1
assert 3 * 5 == 15
assert 3 / 2 == 1.5
assert 10 % 3 == 1
assert 2 ** 3 == 8
1.2.一元运算符
正负号是一元运算符
assert +3 == 3
assert -4 == 0 - 4
assert -(-1) == 1
自加自减也是一元运算符
def a = 2
def b = a++ * 3
assert a == 3 && b == 6
def c = 3
def d = c-- * 2
assert c == 2 && d == 6
def e = 1
def f = ++e + 3
assert e == 2 && f == 5
def g = 4
def h = --g + 1
assert g == 3 && h == 4
1.3. 算数赋值运算符
+=
-=
*=
/=
%=
**=
例子:
def a = 4
a += 3
assert a == 7
def b = 5
b -= 3
assert b == 2
def c = 5
c *= 3
assert c == 15
def d = 10
d /= 2
assert d == 5
def e = 10
e %= 3
assert e == 1
def f = 3
f **= 2
assert f == 9
2.关系运算符
运算符 | 用途 |
---|---|
== |
相等 |
!= |
不等 |
< |
小于 |
<= |
小于等于 |
> |
大于 |
>= |
大于等于 |
例子:
assert 1 + 2 == 3
assert 3 != 4
assert -2 < 3
assert 2 <= 2
assert 3 <= 4
assert 5 > 1
assert 5 >= -2
3.逻辑运算符
有三种逻辑运算符
-
&&
:逻辑与 -
||
:逻辑或 -
!
: 逻辑非
例子
assert !false
assert true && true
assert true || false
3.1.优先级
逻辑非 > 逻辑与 > 逻辑或
assert (!false && false) == false
assert true || true && false
3.2.短路
boolean checkIfCalled() {
called = true
}
called = false
true || checkIfCalled()
assert !called
called = false
false || checkIfCalled()
assert called
called = false
false && checkIfCalled()
assert !called
called = false
true && checkIfCalled()
assert called
4.位运算符
有四种:
-
&
: 与 -
|
: 或 -
^
: 异或 -
~
: 非
int a = 0b00101010
assert a==42
int b = 0b00001000
assert b==8
assert (a & a) == a
assert (a & b) == b
assert (a | a) == a
assert (a | b) == a
int mask = 0b11111111
assert ((a ^ a) & mask) == 0b00000000
assert ((a ^ b) & mask) == 0b00100010
assert ((~a) & mask) == 0b11010101
5.条件运算符
5.1.非运算
assert (!true) == false
assert (!'foo') == false
assert (!'') == true
5.2.三元表达式
下面的代码
if (string!=null && string.length()>0) {
result = 'Found'
} else {
result = 'Not found'
}
可以写成
result = (string!=null && string.length()>0) ? 'Found' : 'Not found'
考虑到 Groovy 的真值表,可以进一步简化为
result = string ? 'Found' : 'Not found'
5.3.艾维斯运算符
代码进一步简化如下
displayName = user.name ? user.name : 'Anonymous'
displayName = user.name ?: 'Anonymous'
6.对象运算符
6.1.空对象安全引用运算符
引用空对象会抛出 NullPointerException
异常。安全引用运算符会避免抛出这个异常,仅仅返回 null 值
def person = Person.find { it.id == 123 }
def name = person?.name
assert name == null
6.2.直接字段访问操作符
通常情况下对字段访问都要经过 getXXX
方法
class User {
public final String name
User(String name) { this.name = name}
String getName() { "Name: $name" }
}
def user = new User('Bob')
assert user.name == 'Name: Bob'
直接字段访问 .@
可以跳过 getXXX
方法,直接获得字段的值
assert user.@name == 'Bob'
6.3.方法指针操作符
方法指针 (.&)
操作符可以获取一个方法指针,后面再调用这个指针
def str = 'example of method reference'
def fun = str.&toUpperCase
def upper = fun()
assert upper == str.toUpperCase()
方法指针获得的值是一个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
7.正则表达式运算符
7.1.模式运算符
模式运算符 (~
) 创建一个 java.util.regex.Pattern
对象
def p = ~/foo/
assert p instanceof Pattern
其实不一定非要用斜杠创建模式,其他类型的字符串也可以充当模式
p = ~'foo'
p = ~"foo"
p = ~$/dollar/slashy $ string/$
p = ~"${pattern}"
7.2.匹配对象操作符
匹配对象操作符 =~
直接创建一个 java.util.regex.Matcher
对象
def text = "some text to match"
def m = text =~ /match/
assert m instanceof Matcher
if (!m) {
throw new RuntimeException("Oops, text not found!")
}
!m
相当于调用 if (!m.find())
7.3.直接匹配操作符
直接匹配操作符 (==~
) 直接返回一个 boolean
值
m = text ==~ /match/
assert m instanceof Boolean
if (m) {
throw new RuntimeException("Should not reach that point!")
}
8.其他操作符
8.1.扩展操作符
将“对象列表”转换成“对象属性的列表”。有点像 Python 的列表生成
class Car {
String make
String model
}
def cars = [
new Car(make: 'Peugeot', model: '508'),
new Car(make: 'Renault', model: 'Clio')]
def makes = cars*.make
assert makes == ['Peugeot', 'Renault']
这种转换是空指针安全的,遇到空指针仅仅返回 null
,而不会抛出 NullPointerException
异常
cars = [
new Car(make: 'Peugeot', model: '508'),
null,
new Car(make: 'Renault', model: 'Clio')]
assert cars*.make == ['Peugeot', null, 'Renault']
assert null*.make == null
扩展操作符的本质是迭代调用并生成列表,因此任何实现了 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']
8.1.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
8.1.2.解包列表元素
def items = [4,5]
def list = [1,2,3,*items,6]
assert list == [1,2,3,4,5,6]
8.1.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]
8.2.范围操作符
范围操作符 (..)
创建一个 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']
8.3.比较操作符
比较操作符 (<=>)
其实就是 compareTo
方法
assert (1 <=> 1) == 0
assert (1 <=> 2) == -1
assert (2 <=> 1) == 1
assert ('a' <=> 'z') == -1
8.4.索引操作符
索引操作符本质上是调用 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'
8.5.成员操作符
成员操作符 (in)
相当于调用了列表的 contains
方法或者 isCase
方法
def list = ['Grace','Rob','Emmy']
assert ('Emmy' in list)
calling list.contains('Emmy')
和 list.isCase('Emmy')
是同样的功能
8.6.同一操作符
在 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)
8.7.类型转换操作符
转型操作符 (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)
8.8.钻石操作符
钻石操作符 (<>)
仅仅是为了兼容 Java 7 中的泛型,在 Groovy 中没有什么用处
List<String> strings = new LinkedList<>()
8.9.调用操作符
调用操作符 ()
隐式调用 call
方法。可以重写 call
实现一些自定义的行为,然后用调用操作符调用
class MyCallable {
int call(int x) {
2*x
}
}
def mc = new MyCallable()
assert mc.call(2) == 4
assert mc(2) == 4
9.操作符优先级
操作符优先级表格
优先级 | 操作符 | 说明 | ||
---|---|---|---|---|
1 | new () |
object creation, explicit parentheses | ||
() {} []
|
method call, closure, literal list/map | |||
. .& .@
|
member access, method closure, field/attribute access | |||
?. * *. *:
|
safe dereferencing, spread, spread-dot, spread-map | |||
~ ! (type)
|
bitwise negate/pattern, not, typecast | |||
[] ++ --
|
list/map/array index, post inc/decrement | |||
2 | ** |
power | ||
3 |
++ -- + -
|
pre inc/decrement, unary plus, unary minus | ||
4 |
* / %
|
multiply, div, modulo | ||
5 |
+ -
|
addition, subtraction | ||
6 |
<< >> >>> .. ..<
|
left/right (unsigned) shift, inclusive/exclusive range | ||
7 |
< <= > >= in
|
instanceof as less/greater than/or equal, in, instanceof, type coercion | ||
8 |
== != <=>
|
equals, not equals, compare to | ||
=~ ==~
|
regex find, regex match | |||
9 | & |
binary/bitwise and | ||
10 | ^ |
binary/bitwise xor | ||
11 | binary/bitwise or | |||
12 | && |
logical and | ||
13 | logical or | |||
14 |
? :
|
ternary conditional | ||
?: |
elvis operator | |||
15 |
= **= *= /= %= += -= <<= >>= >>>= &= ^=
|
= | various assignments |
10.操作符重载
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() |