与Java一样的就不展开了~
除号(/)的特殊行为
Groovy中的除/
和Java的表现不一样:
- 当两个操作数中有一个是
float
或double
时,结果是double
- 当两个操作数都是整型(
short
、char
、byte
、int
、long
或BigInteger
)或者BigDecimal
时,结果是BigDecimal
- 如果要像Java那样取整,需要调用
intdiv
方法
def result = 1 / 3.0f // 当其中有一个是float或double时
println result.class // 结果是:class java.lang.Double
println result // 0.3333333333333333
println 4.intdiv(3) // 结果为1,与Java一样
def newResult = 1 / 2 // 当两个操作数都是整型
println newResult.class // class java.math.BigDecimal
println newResult // 结果是0.5
指数运算符(Power operator)
Groovy中引入了指数运算符**
。如2 ** 3
表示为2的三次方。
// base and exponent are ints and the result can be represented by an Integer
// 基数和指数都是int,所得结果可以用int表示,那么结果就是int类型
assert 2**3 instanceof Integer // 8
assert 10**9 instanceof Integer // 1_000_000_000
// the base is a long, so fit the result in a Long
// (although it could have fit in an Integer)
// 基数是long类型,所以结果也是long类型,尽管用int就足够表示
assert 5L**2 instanceof Long // 25
// the result can't be represented as an Integer or Long, so return a BigInteger
// 当结果超过了int和long的表示范围,用BigInteger表示
assert 100**10 instanceof BigInteger // 10e20
assert 1234**123 instanceof BigInteger // 170515806212727042875...
// the base is a BigDecimal and the exponent a negative int
// but the result can be represented as an Integer
assert 0.5**-2 instanceof Integer // 4
// the base is an int, and the exponent a negative float
// but again, the result can be represented as an Integer
assert 1**-0.3f instanceof Integer // 1
// the base is an int, and the exponent a negative int
// but the result will be calculated as a Double
// (both base and exponent are actually converted to doubles)
assert 10**-1 instanceof Double // 0.1
// the base is a BigDecimal, and the exponent is an int, so return a BigDecimal
assert 1.2**10 instanceof BigDecimal // 6.1917364224
// the base is a float or double, and the exponent is an int
// but the result can only be represented as a Double value
assert 3.4f**5 instanceof Double // 454.35430372146965
assert 5.6d**2 instanceof Double // 31.359999999999996
// the exponent is a decimal value
// and the result can only be represented as a Double value
assert 7.8**1.9 instanceof Double // 49.542708423868476
assert 2**0.1f instanceof Double // 1.0717734636432956
Elvis Operator
在Java中,我们有时会用三元运算符来简化代码,比如下边的例子:
String name = getName(); // 假设这个方法可能返回空值,如果我们想在为空时赋上一个默认值
// 写法1,普通写法
if (name == null) {
name = "unknow";
}
// 写法2,使用三元运算符
name = name != null ? name : "unknow";
在Groovy中,可以使用Elvis operator来进一步简化:
def name = getName()
name = name ?: 'unknown' // 在Groovy真值中,非空也为true
println name
安全访问运算符(Safe navigation operator)
我们可以通过一个点.
来访问一个对象的属性或方法,但很多时候我们拿到的变量可能是null。这时如果我们直接使用.
去访问,就有可能抛出空指针异常。而Groovy的安全访问运算符?.
可以很好地解决这个问题:
def person = getPerson() // 假设该方法可能返回null
def name = person?.name // 如果person不为null,那返回具体的值;如果为null,也不会抛出异常,而是返回null
直接属性访问运算符(Direct field access operator)
先看一个例子:
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' // 这里看似是访问属性name,但其实是调用getName方法
上面例子中,我们直接使用user.name
其实相当于user.getName()
。如果需要直接访问属性,需要使用.@
这个运算符:
// 接上边的例子
assert user.@name == 'Bob'
方法指针运算符(Method pointer operator)
使用.&
可以取一个方法的指针,而所谓的方法指针,其实是Groovy中的闭包:
def str = 'example of method reference'
def fun = str.&toUpperCase // 取String的toUpperCase方法指针
println fun.class // class org.codehaus.groovy.runtime.MethodClosure
def upper = fun() // 这里相当于调用了方法
assert upper == str.toUpperCase()
展开运算符(Spread Operator)
Groovy中的展开运算符(*.)很有意思,它用于展开集合元素。
class Car {
String make
String model
}
def cars = [
new Car(make: 'Peugeot', model: '508'),
new Car(make: 'Renault', model: 'Clio')]
def makes = cars*.make // 相当于访问了每一个元素的make
assert makes == ['Peugeot', 'Renault'] // 结果还是一个列表
范围运算符(Range operator)
使用..
可以定义一个范围:
def range = 0..5
println range.class // class groovy.lang.IntRange
assert (0..5).collect() == [0, 1, 2, 3, 4, 5]
assert (0..<5).collect() == [0, 1, 2, 3, 4] // 相当于左闭右开区间
assert (0..5) instanceof List // Range实现了List接口
assert (0..5).size() == 6
飞船运算符(Spaceship operator)
<==>
像不像一个宇宙飞船?相当于调用compareTo
方法:
assert (1 <=> 1) == 0
assert (1 <=> 2) == -1
assert (2 <=> 1) == 1
assert ('a' <=> 'z') == -1
成员运算符(Membership operator)
in
相当于inCase
方法,当用在列表上时,相当于调用列表的contains
方法:
def list = ['Grace', 'Rob', 'Emmy']
assert ('Emmy' in list) // 相当于list.contains('Emmy')或list.isCase('Emmy')
身份运算符(Identity operator)
在Groovy中==
相当于调用equals
方法,如果要判断两个对象是否是同一个,需要使用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 // 相当于list.equals(list2)
assert !list1.is(list2)
运算符重载(Operator overloading)
Groovy中支持运算符重载,其实也就是实现约定好的方法:
class Bucket {
int size
Bucket(int size) { this.size = size }
Bucket plus(Bucket other) { // 重载这个以实现+操作
return new Bucket(this.size + other.size)
}
}
def b1 = new Bucket(4)
def b2 = new Bucket(11)
assert (b1 + b2).size == 15 // 这里相当于(b1.plus(b2)).size
下面是支持重载的运算符与相应方法的对照表: