與Java一樣的就不展開了~
除號(hào)(/)的特殊行為
Groovy中的除/
和Java的表現(xiàn)不一樣:
- 當(dāng)兩個(gè)操作數(shù)中有一個(gè)是
float
或double
時(shí)换帜,結(jié)果是double
- 當(dāng)兩個(gè)操作數(shù)都是整型(
short
酿傍、char
构韵、byte
泉沾、int
、long
或BigInteger
)或者BigDecimal
時(shí)箩兽,結(jié)果是BigDecimal
- 如果要像Java那樣取整薇溃,需要調(diào)用
intdiv
方法
def result = 1 / 3.0f // 當(dāng)其中有一個(gè)是float或double時(shí)
println result.class // 結(jié)果是:class java.lang.Double
println result // 0.3333333333333333
println 4.intdiv(3) // 結(jié)果為1,與Java一樣
def newResult = 1 / 2 // 當(dāng)兩個(gè)操作數(shù)都是整型
println newResult.class // class java.math.BigDecimal
println newResult // 結(jié)果是0.5
指數(shù)運(yùn)算符(Power operator)
Groovy中引入了指數(shù)運(yùn)算符**
。如2 ** 3
表示為2的三次方梅肤。
// base and exponent are ints and the result can be represented by an Integer
// 基數(shù)和指數(shù)都是int,所得結(jié)果可以用int表示司蔬,那么結(jié)果就是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)
// 基數(shù)是long類型,所以結(jié)果也是long類型凭语,盡管用int就足夠表示
assert 5L**2 instanceof Long // 25
// the result can't be represented as an Integer or Long, so return a BigInteger
// 當(dāng)結(jié)果超過了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中葱她,我們有時(shí)會(huì)用三元運(yùn)算符來簡(jiǎn)化代碼,比如下邊的例子:
String name = getName(); // 假設(shè)這個(gè)方法可能返回空值似扔,如果我們想在為空時(shí)賦上一個(gè)默認(rèn)值
// 寫法1吨些,普通寫法
if (name == null) {
name = "unknow";
}
// 寫法2,使用三元運(yùn)算符
name = name 炒辉!= null ? name : "unknow";
在Groovy中豪墅,可以使用Elvis operator來進(jìn)一步簡(jiǎn)化:
def name = getName()
name = name ?: 'unknown' // 在Groovy真值中,非空也為true
println name
安全訪問運(yùn)算符(Safe navigation operator)
我們可以通過一個(gè)點(diǎn).
來訪問一個(gè)對(duì)象的屬性或方法黔寇,但很多時(shí)候我們拿到的變量可能是null偶器。這時(shí)如果我們直接使用.
去訪問,就有可能拋出空指針異常缝裤。而Groovy的安全訪問運(yùn)算符?.
可以很好地解決這個(gè)問題:
def person = getPerson() // 假設(shè)該方法可能返回null
def name = person?.name // 如果person不為null屏轰,那返回具體的值;如果為null憋飞,也不會(huì)拋出異常霎苗,而是返回null
直接屬性訪問運(yùn)算符(Direct field access operator)
先看一個(gè)例子:
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,但其實(shí)是調(diào)用getName方法
上面例子中,我們直接使用user.name
其實(shí)相當(dāng)于user.getName()
榛做。如果需要直接訪問屬性唁盏,需要使用.@
這個(gè)運(yùn)算符:
// 接上邊的例子
assert user.@name == 'Bob'
方法指針運(yùn)算符(Method pointer operator)
使用.&
可以取一個(gè)方法的指針内狸,而所謂的方法指針,其實(shí)是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() // 這里相當(dāng)于調(diào)用了方法
assert upper == str.toUpperCase()
展開運(yùn)算符(Spread Operator)
Groovy中的展開運(yùn)算符(*.)很有意思厘擂,它用于展開集合元素昆淡。
class Car {
String make
String model
}
def cars = [
new Car(make: 'Peugeot', model: '508'),
new Car(make: 'Renault', model: 'Clio')]
def makes = cars*.make // 相當(dāng)于訪問了每一個(gè)元素的make
assert makes == ['Peugeot', 'Renault'] // 結(jié)果還是一個(gè)列表
范圍運(yùn)算符(Range operator)
使用..
可以定義一個(gè)范圍:
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] // 相當(dāng)于左閉右開區(qū)間
assert (0..5) instanceof List // Range實(shí)現(xiàn)了List接口
assert (0..5).size() == 6
飛船運(yùn)算符(Spaceship operator)
<==>
像不像一個(gè)宇宙飛船?相當(dāng)于調(diào)用compareTo
方法:
assert (1 <=> 1) == 0
assert (1 <=> 2) == -1
assert (2 <=> 1) == 1
assert ('a' <=> 'z') == -1
成員運(yùn)算符(Membership operator)
in
相當(dāng)于inCase
方法刽严,當(dāng)用在列表上時(shí)昂灵,相當(dāng)于調(diào)用列表的contains
方法:
def list = ['Grace', 'Rob', 'Emmy']
assert ('Emmy' in list) // 相當(dāng)于list.contains('Emmy')或list.isCase('Emmy')
身份運(yùn)算符(Identity operator)
在Groovy中==
相當(dāng)于調(diào)用equals
方法,如果要判斷兩個(gè)對(duì)象是否是同一個(gè)港庄,需要使用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 // 相當(dāng)于list.equals(list2)
assert !list1.is(list2)
運(yùn)算符重載(Operator overloading)
Groovy中支持運(yùn)算符重載倔既,其實(shí)也就是實(shí)現(xiàn)約定好的方法:
class Bucket {
int size
Bucket(int size) { this.size = size }
Bucket plus(Bucket other) { // 重載這個(gè)以實(shí)現(xiàn)+操作
return new Bucket(this.size + other.size)
}
}
def b1 = new Bucket(4)
def b2 = new Bucket(11)
assert (b1 + b2).size == 15 // 這里相當(dāng)于(b1.plus(b2)).size
下面是支持重載的運(yùn)算符與相應(yīng)方法的對(duì)照表: