Groovy之操作符
這里對(duì)Groovy中常見的操作符進(jìn)行介紹

操作符用法
算術(shù)操作符
同Java一樣,在算術(shù)操作符方面Groovy并無二致。示例代碼如下所示
class?OperatorDemo?{????
????static?void?arithmetic()?{
????????//?加
????????assert?3+4?==?7
????????//?加并賦值
????????def?foo1?=?3
????????foo1?+=?4
????????assert?foo1?==?7
????????//?減
????????assert?4-3?==?1
????????//?減并賦值
????????def?foo2?=?4
????????foo2?-=?3
????????assert?foo2?==?1
????????//?乘
????????assert?4*3?==?12
????????//?乘并賦值
????????def?foo3?=?4
????????foo3?*=3
????????assert?foo3?==?12
????????//?除
????????assert?12/3?==?4
????????//?除并賦值
????????def?foo4?=?12
????????foo4?/=?3
????????assert?foo4?==4
????????//?求余
????????assert?13%3?==?1
????????//?求余并賦值
????????def?foo5?=?13
????????foo5?%=?3
????????assert?foo5?==?1
????????//?冪
????????assert?2**3?==?8
????????//?冪并賦值
????????def?foo6?=?2
????????foo6?**=?3
????????assert?foo6?==?8
????????//?一元運(yùn)算符?+?表示?正數(shù)
????????assert?+3?==?3
????????//?一元運(yùn)算符?-?表示?負(fù)數(shù)
????????assert?-4?==?0-4
????????assert?-(-11)??==?11
????????//?后綴自增
????????def?a1?=?2
????????def?b1?=?a1++
????????assert?a1?==?3
????????assert?b1?==?2
????????//?前綴自增
????????def?a2?=?2
????????def?b2?=?++a2
????????assert?a2?==?3
????????assert?b2?==?3
????????//?后綴自減
????????def?a3?=?2
????????def?b3?=?a3--
????????assert?a3?==?1
????????assert?b3?==?2
????????//?前綴自減
????????def?a4?=?2
????????def?b4?=?--a4
????????assert?a4?==?1
????????assert?b4?==?1
????}
}???
關(guān)系運(yùn)算符
Groovy的關(guān)系運(yùn)算符示例如下所示
class?OperatorDemo?{????
????static?void?relational()?{
????????//?相等
????????assert?(3*4)?==?(10+2)
????????//?不相等
????????assert?3?!=?4
????????//?小于
????????assert?3?4
????????//?小于等于
????????assert?3<=4
????????assert?4<=4
????????//?大于
????????assert?5?>?4
????????
????????//?大于等于
????????assert?5>=4
????????assert?5>=5
????}
}
邏輯運(yùn)算符
Groovy在邏輯運(yùn)算符支持常見的與、或、非,同時(shí)具備短路求值的特點(diǎn)
class?OperatorDemo?{????
????static?void?logical()?{
????????//?邏輯與,?支持短路求值
????????assert?true?&&?true
????????
????????//?邏輯或,?支持短路求值
????????assert?false?||?true
????????
????????//?邏輯非
????????assert?!false
????}
}
位運(yùn)算
Groovy與Java一樣,同樣支持位運(yùn)算。示例如下所示
class?OperatorDemo?{
????static?void?bit()?{
????????//?按位與
????????int?a?=?0b1010??//?a?=?10
????????assert?a?==?10
????????int?b?=?0b0110??//?b?=?6
????????assert?b?==?6
????????int?c?=?0b0010??//?c?=?2
????????assert?c?==2
????????assert?(a&b)?==?c
????????//?按位或
????????int?d?=?0b1110??//?d?=?14
????????assert?d?==?14
????????assert?(a|b)?==?d
????????//?按位異或
????????int?e?=?0b1100
????????assert?e?==?12
????????assert?(a^b)?==?e
????????//?按位取反
????????byte?f?=?0b00001111
????????assert?f?==?15
????????byte?h?=?0b11110000
????????assert?h?==?-16
????????assert?(~f)?==?h
????????//?左移
????????byte?i?=?0b00000011
????????assert?i?==?3
????????byte?j?=?0b00001100
????????assert?j?==?12
????????assert?(i<<2)?==?j
????????//?右移
????????assert?(j>>2)?==?i
????????//?右移:?左邊使用原符號(hào)位進(jìn)行填充,?右邊超出部分直接丟棄
????????byte?k?=?0b11111011
????????assert?k?==?-5
????????byte?p?=?0b11111110
????????assert?p?==?-2
????????assert?(k>>2)?==?p
????????//?無符號(hào)右移:?左邊使用0進(jìn)行填充,?右邊超出部分直接丟棄
????????int?q?=?0x8022_11ff?//?數(shù)字支持使用下劃線進(jìn)行劃分,?便于人眼查看
????????assert?q?==?-2145250817
????????int?r?=?0x0080_2211
????????assert?r?==?8397329
????????assert?(q>>>8)?==?r
????}
}
條件運(yùn)算符
Groovy不僅提供了傳統(tǒng)的三元運(yùn)算符。還特別提供了Elvis運(yùn)算符、Elvis賦值運(yùn)算符。對(duì)于前者而言,如果Elvis運(yùn)算符左邊的操作數(shù)判定為真,則返回左邊操作數(shù); 否則返回右邊的操作數(shù);對(duì)于后者而言,Elvis賦值運(yùn)算符, 其是對(duì)Elvis運(yùn)算符的進(jìn)一步簡(jiǎn)化, 省去了再次賦值操作。示例如下所示
class?OperatorDemo?{
????static?void?conditional()?{
????????//?三元運(yùn)算符
????????def?a1?=?(2>1)???3?:?4
????????assert?a1?==?3
????????def?a2?=?(2>3)???3?:?4
????????assert?a2?==?4
????????//?Elvis?運(yùn)算符,?如果?:運(yùn)算符左邊的操作數(shù)判定為真,則返回左邊操作數(shù);?否則返回右邊的操作數(shù)
????????//?可以視為簡(jiǎn)版的三元運(yùn)算符
????????def?b1?=?"Hello?World"
????????//??等同于?b1?=?(b1!=null?||?b1!="")???b1?:?"Hi"
????????b1?=?b1??:?"Hi"?//?非空字符串視為真
????????assert?b1?==?"Hello?World"
????????//?Elvis?運(yùn)算符
????????def?b2?=?""
????????b2?=?b2??:?"Hi"
????????assert?b2?==?"Hi"
????????//?Elvis賦值?運(yùn)算符,?其是對(duì)Elvis運(yùn)算符的進(jìn)一步簡(jiǎn)化,?省去了再次賦值操作
????????def?c1?=?"Hello?World"
????????c1??=?"Hi"
????????assert?c1?==?"Hello?World"
????????def?c2?=?""
????????c2??=?"Hi"
????????assert?c2?==?"Hi"
????}
}
正則操作符
特別地,Groovy針對(duì)正則操作提供了相應(yīng)的操作符。示例如下所示
class?OperatorDemo?{
????static?void?regular()?{
????????String?regex?=?/\S+\s+\S+/
????????//?模式操作符?~
????????def?pattern1?=?~regex
????????assert?pattern1?instanceof?Pattern
????????def?text1?=?"One?Two?Three?Four?Five"
????????def?matcher1?=?pattern1.matcher(text1)
????????assert?matcher1?instanceof?Matcher
????????assert?matcher1.size()?==?2
????????assert?matcher1[0]?==?"One?Two"
????????assert?matcher1[1]?==?"Three?Four"
????????//?查找運(yùn)算符?=~
????????//?具體地,其會(huì)在文本text1上應(yīng)用正則表達(dá)式regex,?生成matcher
????????def?matcher2?=?(text1?=~?regex)
????????assert?matcher2?instanceof?Matcher
????????assert?matcher2.size()?==?2
????????assert?matcher2[0]?==?"One?Two"
????????assert?matcher2[1]?==?"Three?Four"
????????//?匹配運(yùn)算符?==~,?其是完整的匹配,?而非部分匹配
????????boolean?b1?=?"One?Two?Three?Four"?==~?regex
????????boolean?b2?=?"One?Two"?==~?regex
????????assert?b1?==?false
????????assert?b2?==?true
????}
}
對(duì)象操作符
Groovy對(duì)于對(duì)象引用提供了豐富的操作符。需要特別提醒的是,在Java中對(duì)兩個(gè)對(duì)象引用使用==操作符比較的是兩個(gè)對(duì)象的地址是否一樣;而在Groovy中==操作符用于比較兩個(gè)對(duì)象的內(nèi)容是否一樣,事實(shí)上該操作符是通過equals方法實(shí)現(xiàn)的。當(dāng)然Groovy自然也是支持比較兩個(gè)對(duì)象的地址,其提供了===操作符。事實(shí)上該操作符是通過is方法實(shí)現(xiàn)的。示例代碼如下所示
class?OperatorDemo?{?
????static?void?object()?{
????????def?person1?=?new?Person("remark":?"領(lǐng)軍人才")
????????//?通過.操作符訪問字段
????????person1.name?=?"Aaron"
????????assert?person1.name?==?"Aaron"
????????//?通過.操作符修改字段實(shí)際上是隱式調(diào)用setter方法
????????person1.age?=?18
????????assert?person1.age?==?218
????????//?通過.操作符獲取字段實(shí)際上是隱式調(diào)用getter方法
????????assert?person1.remark?==?":?領(lǐng)軍人才"
????????//?通過.@運(yùn)算符可以實(shí)現(xiàn)直接訪問字段,?而不是通過隱式調(diào)用getter、setter方法實(shí)現(xiàn)
????????assert?person1.@remark?==?"領(lǐng)軍人才"
????????person1.@age?=?17
????????assert?person1.age?==?17
????????//?安全引用操作符
????????Person?person2?=?null
????????//?如果?.安全引用操作符的引用為null,?則不會(huì)調(diào)用方法,?而是直接返回null以避免NPE
????????assert?person2?.getAge()?==?null
????????assert?person1?.getAge()?==?17
????????//?方法指針運(yùn)算符
????????MethodClosure?fun1?=?person1.&getAge
????????//?方法指針的類型是閉包
????????assert?fun1?instanceof?Closure
????????assert?fun1()?==?17
????????assert?fun1.call()?==?17
????????//?方法指針同樣支持多分派
????????def?fun3?=?person1.&test1
????????assert?fun3.call("Bye")?==?"Aaron:?Bye"
????????assert?fun3.call(3)?==?"<17?+?3>?-->>?20"
????????//?可通過new獲取構(gòu)造器的方法指針
????????def?fun4?=?Person.&new
????????Person?person3?=?fun4.call("name":"Bob")
????????assert?person3.name?==?"Bob"
????????//?通過類先獲取非靜態(tài)方法的方法指針
????????def?fun2?=?String.&toUpperCase
????????//?在執(zhí)行閉包時(shí),?再傳入該類的實(shí)例,?以作為方法的調(diào)用者
????????assert?fun2.call("Hello")?==?"HELLO"
????????def?fun5?=?Person.&test1
????????assert?fun5.call(?person1,?"welcome"?)?==?"Aaron:?welcome"
????????//?方法指針運(yùn)算符同樣適用于靜態(tài)方法
????????def?fun6?=?String.&valueOf
????????assert?fun6.call(?false?)?==?"false"
????????assert?fun6.call(?996?)?==?"996"
????????//?Groovy對(duì)Java?8的::方法引用運(yùn)算符保持支持兼容
????????def?list1?=?["71","2","4"].stream()
????????????.map(?Integer::valueOf?)
????????????.collect(?Collectors.toList()?)
????????assert?list1?==?[71,2,4]
????????//?list1a,?list1b?引用地址相同
????????def?list1a?=?[1,2]?as?LinkedList
????????def?list1b?=?list1a
????????//?另外一個(gè)包含相同元素的列表
????????def?list2?=?[1,2]?as?LinkedList
????????//?判斷兩個(gè)引用的內(nèi)容是否相同
????????//?==?運(yùn)算符所對(duì)應(yīng)的方法是equals
????????assert?list1a?==?list2
????????assert?list1a.equals(?list2?)
????????//?類似地,?!=運(yùn)算符是對(duì)equals方法的結(jié)果進(jìn)行否定
????????assert?list1a?!=?[985,211]
????????assert?!(?list1a.equals([985,211])?)
????????//?判斷兩個(gè)引用的地址是否相同
????????//?===運(yùn)算符對(duì)應(yīng)is方法
????????assert?list1a?===?list1a
????????assert?list1a.is(list1b)
????????//?判斷兩個(gè)對(duì)象的引用地址是否不同
????????//?類似地,?!==運(yùn)算符是對(duì)is方法的結(jié)果進(jìn)行否定
????????assert?list1a?!==?list2
????????assert?!(?list1a.is(list2)?)
????}
}
class?Person?{
????String?name
????Integer?age
????String?remark
????void?setAge(Integer?age)?{
????????this.age?=?200?+?age
????}
????String?getRemark()?{
????????return?":?$remark"
????}
????/**
?????*?實(shí)現(xiàn)equals方法,?實(shí)現(xiàn)重載==運(yùn)算符
?????*?@param?other
?????*?@return
?????*/
????@Override
????boolean?equals(Object?other)?{
????????if?(!other
????????????||?!(other?instanceof?Person)
????????????||?name?!=?other.name
????????????||?age?!=?other.age
????????????||?remark?!=?other.remark?)?{
????????????return??false
????????}
????????return?true
????}
????String?test1(String?msg)?{
????????return?"$name:?$msg"
????}
????String?test1(Integer?num)?{
????????return?"<${this.age}?+?${num}>?-->>?${this.age+num}"
????}
}
其它
Groovy中其它部分常見的操作符,示例如下所示
class?OperatorDemo?{
????static?void?other()?{
????????//?飛船運(yùn)算符,?通過調(diào)用Comparable接口的compareTo方法進(jìn)行比較
????????//?15==15
????????assert?(15?<=>?15)?==?0
????????//?44>22
????????assert?(44?<=>?22)?==?1
????????//?22<44
????????assert?(22?<=>?44)?==?-1
????????//?安全索引運(yùn)算符?[],?作用類似于?.安全引用操作符
????????//?避免由于數(shù)組為null而導(dǎo)致的NPE
????????String[]?array1?=?["Amy",?"Aaron"]
????????array1?[1]?=?"Bob"
????????assert?array1?[0]?==?"Amy"
????????assert?array1?[1]?==?"Bob"
????????array1?=?null
????????//?array1為null,?將不會(huì)應(yīng)用索而是直接返回null
????????assert?array1?[0]?==?null
????????//?安全索引運(yùn)算符同樣適用于Map
????????def?map1?=?[:]
????????map1?["Aaron"]?=?18
????????assert?map1?["Aaron"]?==?18
????????map1?=?null
????????assert?map1?["Aaron"]?==?null
????????//?成員操作符
????????def?list1?=?["MicroSoft",?"Apple",?"Xiaomi",?"FaceBook"]
????????//?判定Apple是否是list1的成員
????????assert?"Apple"?in?list1
????????//?等效于調(diào)用isCase方法
????????assert?list1.isCase(?"Apple"?)
????????assert?!("Huawei"?in?list1)
????????assert?996?in?Integer
????????//?等效于調(diào)用isCase方法
????????assert?Integer.isCase(996)
????????assert?!(3.14f?in?Integer)
????????assert?3.14f?in?Float
????????assert?Float.isCase(?3.1f?)
????}
}
操作符重載
在Groovy中,部分操作符是有對(duì)應(yīng)的方法。換言之,通過操作符或方法調(diào)用在本質(zhì)上效果是一致的。但操作符一旦有對(duì)應(yīng)的方法,就為我們提供了另外一種編程方式,即進(jìn)行操作符的重載。在特殊場(chǎng)景下,操作符的重載可以大大方便我們的使用。比如期望通過乘法符號(hào)計(jì)算兩個(gè)矩陣的乘積,在Java中這顯然是不可能。因?yàn)槲覀儾荒茏远x乘法操作符的具體邏輯,而在Groovy中則可以在我們自定義的矩陣類中通過重載乘法操作符實(shí)現(xiàn)。這里給出Groovy可以進(jìn)行重載的操作符及對(duì)應(yīng)的方法名

下面給出一個(gè)進(jìn)行重載操作符的示例,方便理解、使用
class?OperatorOverLoad?{
????static?void?main(String[]?args){
????????testPlus()
????????testNext()
????????testCall()
????}
????
????static?void?testNext()?{
????????Food?food1?=?new?Food("西瓜",?14)
????????food1++
????????assert?food1.toString()?==?"Food?{?type=西瓜,?num=15?}"
????????def?food2?=?new?Food(type:?"哈蜜瓜"?)
????????food2++
????????assert?food2.toString()?==?"Food?{?type=哈蜜瓜,?num=1?}"
????}
????static?void?testPlus()?{
????????Food?food1?=?new?Food("橘子",?1)
????????Food?food2?=?new?Food("橘子",?2)
????????Food?food3?=?new?Food("type":?"橘子")
????????Food?food4?=?new?Food("type":?"蘋果")
????????assert?(food1?+?food2).toString()?==?"Food?{?type=橘子,?num=3?}"
????????assert?(food2?+?food3).toString()?==?"Food?{?type=橘子,?num=2?}"
????????assert?(food1?+?food4)?==?null
????}
????static?void?testCall()?{
????????Food?food1?=?new?Food("檸檬",?21)
????????def?str?=?food1()
????????//?顯式調(diào)用call方法
????????assert?food1.call()?==?"Food?{?type=檸檬,?num=21?}"
????????//?通過?調(diào)用運(yùn)算符()?調(diào)用?call方法
????????assert?food1()?==?"Food?{?type=檸檬,?num=21?}"
????}
}
class?Food?{
????String?type
????Integer?num
????Food(String?type,?Integer?num)?{
????????this.type?=?type
????????this.num?=?num
????}
????Food()?{
????}
????/**
?????*?重載加法運(yùn)算符+
?????*?@param?other
?????*?@return
?????*/
????Food?plus(Food?other)?{
????????if(?!this.type?||?this.type?!=?other?.type?)?{
????????????return?null
????????}
????????Integer?num1?=?this.num??:?0
????????Integer?num2?=?other.num??:?0
????????Integer?result?=?num1?+?num2
????????return?new?Food("type":type,?"num":?result)
????}
????/**
?????*?重載自增運(yùn)算符++
?????*?@return
?????*/
????Food?next()?{
????????this.num??=?0
????????this.num++
????????return?this
????}
????/**
?????*?重載調(diào)用運(yùn)算符()
?????*?@return
?????*/
????String?call()?{
????????return?toString()
????}
????@Override
????String?toString()?{
????????return?"Food?{?type=$type,?num=$num?}"
????}
}
參考文獻(xiàn)
Groovy In Action · 2nd Edition ? Dierk K?nig、Guillaume Laforge著
