Groovy編程入門攻略。本站提示廣大學習愛好者:(Groovy編程入門攻略)文章只能為提供參考,不一定能成為您想要的結果。以下是Groovy編程入門攻略正文
當一個Java開辟人員參加到Groovy的開辟之旅的時刻,他/她常常帶著Java思惟去思慮,並慢慢地進修Groovy,每次進修一個特征,這會讓他漸漸變得更有發明性和寫出更相符說話習氣的Groovy代碼。這篇文章的目標是引誘這些開辟人員去進修根本的Groovy編程作風,進修新的操作技能,新的說話特征,例如閉包等等。這篇文章其實不會具體鋪開描寫,而是給讀者一個入門的指引,並讓讀者在今後的深刻進修打好基本。假如你愛好這篇文章,可以進獻你的一份力氣去豐碩它。
無分號
C / C++ / C# / Java開辟者,常常隨處應用分號。雖然Groovy支撐99%的java語法,有時你只需簡略的把java代碼粘貼到Groovy法式裡,然則卻帶著一年夜堆分號。在Groovy裡,分號是可選的,你可以省略他們,更經常使用的用法是刪除它們。
前往症結字 (Return) 變得可選
在Groovy的世界外面,辦法的法式塊開頭可以不寫'return'症結字而照樣前往值。特別是關於語句不多的辦法和閉包。如許的寫法更幽美更簡練:
String toString() {return"a server"} String toString() {"a server"}
但有些情形卻不那末幽美,例如你應用了變量,並在兩行外面湧現兩次:
def props() { def m1 = [a:1, b:2] m2 = m1.findAll { k, v -> v %2==0} m2.c =3 m2 }在這個例子外面,或許是在最初一個表達式前面加上一個空行,抑或是顯式地加上'return'症結字會令代碼更有可讀性。
我本身小我習氣,有時刻愛好用return症結字,有時刻又不愛好,這跟小我口胃有關系吧。然則,更多時刻,例如在閉包外面,我更愛好不寫return症結字。所以即便return症結字是可選的,也不會強迫你不克不及應用它,假如你以為它會打破代碼的可讀性。
謹嚴為上,但是當你應用def症結字界說,而並不是用取代詳細某一個類型去界說的辦法,有時刻你會驚異的發明最初一條表達式會作為前往成果而前往。所以更多時刻更推舉應用詳細的類型(例如void或類型)作為前往類型。在我們下面的例子中,假如我們忘卻了把m2放在最初一行並作為前往值,那末最初的一個表達式將是m2.c = 3,如許會招致數值3作為前往值前往,而不是我們等待的成果。
形如if/else語句,try/cath語句異樣可以前往值,由於它們外面都有"最初一個表達式"會被前往。
def foo(n) { if(n ==1) { "Roshan" }else{ "Dawrani" } } assertfoo(1) =="Roshan" assertfoo(2) =="Dawrani"
Def 和 類型
當我們評論辯論def和類型,我常常會發明一些開辟人員既用'def'又用類型。然則'def'在這裡是過剩的。所以,年夜家要做一個選擇,要不消'def', 要不就用類型。
所以不要寫出以下的代碼:
def String name = "Guillaume"
可以寫成
String name ="Guillaume"
當我們在Groovy外面應用def,真實的類型是Object(所以你可以向用def界說的變量,賦值任何的對象,而且,當一個辦法是用def作為前往值的時刻,可以以任何對象類型作而前往)。
當一個辦法未聲明變量類型,你可使用def,然則這不是必需的,所以可以省略他,所以可以取代上面的語句:
void doSomething(def param1, def param2) { }
推舉:
void doSomething(param1, param2) { }
然則,就如我們在文章末尾提到的,我們更推舉為辦法的參數指定類型。如許可以贊助進步代碼的可讀性,也能夠贊助IDE對象使代碼完全,或許應用Groovy的靜態類型檢討或靜態編譯功效。
別的一個def過剩的處所是界說結構函數,應防止應用:
class MyClass { def MyClass() {} }
應去失落 結構函數前的'def':
classMyClass { MyClass() {} }
默許的Public
默許情形,Groovy會以為類和辦法是界說為'public'的。所以你不須要顯式的聲明public。當須要聲明為非public的時刻,你須要顯式的指定潤飾符。
所以免以下寫法:
public class Server { public String toString() {return "a server"} }
推舉應用以下簡練的寫法
class Server { String toString() {"a server"} }
你能夠會關懷包規模內的可拜訪性成績。現實上,Groovy許可省略public, 是由於這個包規模外面默許情形下是不支撐public,然則現實上有別的一個Groovy正文語法去完成可拜訪性:
class Server { @Package ScopeCluster cluster }
省略圓括號
Groovy許可你在頂級表達式中省略圓括號,例如println語句:
println"Hello" method a, b
比較:
println("Hello") method(a, b)
當辦法的最初一個參數是閉包的時刻,例如應用Groovy的'each'迭代機制,你可以把閉包放在括號以外,乃至省略括號:
list.each( { println it } ) list.each(){ println it } list.each { println it }
平日我們推舉應用下面第三種寫法,它顯得更天然,由於沒有圓括號是何等的過剩!
然則Groovy在某些情形其實不許可你去失落圓括號。就像我之前說的,頂級表達式可以省略,然則嵌套的辦法或許賦值表達式的左邊,你卻不克不及省略:
def foo(n) { n }
println foo1// 毛病寫法 def m = foo1
類,一級國民
在Groovy外面,.class後綴是不須要的,有點像Java的instanceof。
例如:
connection.doPost(BASE_URI +"/modify.hqu", params, ResourcesResponse.class)
上面我們應用GString,並應用第一類國民:
connection.doPost("${BASE_URI}/modify.hqu", params, ResourcesResponse)
Getters和Setters
在Groovy的世界裡,getters和setters就是我們常說的"屬性",Groovy供給一個正文語法捷徑給我們去拜訪或給屬性賦值。摒棄java方法的getters/setters,你可使用正文語法:
resourceGroup.getResourcePrototype().getName() == SERVER_TYPE_NAME resourceGroup.resourcePrototype.name == SERVER_TYPE_NAME resourcePrototype.setName("something") resourcePrototype.name = "something"
當你用Groovy寫beans的時刻,我們平日叫做POGOs(通俗Groovy對象),你不須要本身創立屬性,和getters/setters辦法,而是留給Groovy編譯器來完成。
所以,不再須要如許去寫:
class Person { private String name String getName() {returnname } void setName(String name) {this.name = name } }
而是:
class Person { String name }
就如你看到的,一個簡練的"屬性"其實不帶任何的拜訪潤飾符,會讓Groovy編譯器為你主動生成一個公有的屬性和getter和setter辦法。
當你在Java中應用如許一個POGOs對象,getter和setter辦法實際上是存在的,固然跟正常的寫法無異。
固然編譯器可以創立getter/setter辦法,然則當你須要在這辦法外面增長一些特別的邏輯或許跟默許的getter/setter辦法紛歧樣,你可以本身去界說它,編譯器主動會選擇你的邏輯取代默許邏輯。
用定名參數和默許結構器初始化beans
有如許一個bean:
class Server { String name Cluster cluster }
為防止像上面如許的費事:
def server =newServer() server.name ="Obelix" server.cluster = aCluster
你可使用定名參數和默許結構器(起首會挪用結構器,然後順次挪用setter辦法):
def server =newServer(name:"Obelix", cluster: aCluster)
在統一個bean外面應用with()語法處置反復操作
默許結構器中,定名參數在創立新的實例時是一件非常風趣的工作。然則當你須要更新一個實例時,你能否須要反復地在變量前反復敲打'server'這個前綴呢?謎底能否定的,由於多虧了with()語句,Groovy會主動為你填上:
server.name = application.name server.status = status server.sessionCount =3 server.start() server.stop()
比較:
server.with { name = application.name status = status sessionCount =3 start() stop() }
equals 和 ==
Java世界裡,==就相當於Groovy外面的is()辦法,別的Groovy的==就是聰慧的equal()辦法!
當你須要比擬對象的援用的時刻,你應當應用Groovy的==,由於他會幫你避開NullPointerException,而你就不須要關懷操作符的左邊或右邊能否為null。
不該該如許寫:
status !=null&& status.equals(ControlConstants.STATUS_COMPLETED)
而是:
status == ControlConstants.STATUS_COMPLETED
GStrings ()
我們常常再JAVA外面應用string和變量銜接,並應用年夜量的雙引號,加號,還有\n字符去創立新的一行。而應用插值字符串(在Groovy外面叫做GStrings),可以簡化我們的代碼寫法:
throw new Exception("Unable to convert resource: "+ resource)
比較:
throw new Exception("Unable to convert resource: ${resource}")
在花括號外面,你可以聽任何的表達式,而不單單是變量。關於簡略的變量,或許變量屬性,你乃至可以丟失落花括號:
throw new Exception("Unable to convert resource: $resource")
你乃至可以經由過程閉包正文(${-> resource})對表達式停止延遲盤算。當GString變量強迫轉換為String變量的時刻,它會主動盤算閉包的值,並經由過程挪用toString()辦法作為前往值。例如:
int i =3 def s1 ="i's value is: ${i}" def s2 ="i's value is: ${-> i}" i++ asserts1 =="i's value is: 3"// 事後盤算,在創立的時刻賦值 asserts2 =="i's value is: 4"// 延遲盤算,應用最新的變量值
在Java外面,字符串聯接是非常的包袱:
throw new PluginException("Failed to execute command list-applications:"+ " The group with name "+ parameterMap.groupname[0] + " is not compatible group of type "+ SERVER_TYPE_NAME)
你可使用 \ 持續字符 (這不同等於多行文本)
throw new PluginException("Failed to execute command list-applications: \ The group with name ${parameterMap.groupname[0]} \ is not compatible group of type ${SERVER_TYPE_NAME}")
或許應用三個雙引號完成多行文本:
throw new PluginException("""Failed to execute command list-applications: The group with name ${parameterMap.groupname[0]} is not compatible group of type ${SERVER_TYPE_NAME)}""")
別的,你也能夠應用.stripIndent()函數完成刪除多行文本外面的左邊過剩空格。
同時請留意Groovy外面單引號和雙引號的差別:單引號平日用來創立Java字符串,不帶任何的插值變量,而雙引號可以創立Java字符串,也能夠用來創立帶插值變量的GStrings。
關於多行字符串,你可使用三個引號:例如在GStrings變量應用三個雙引號,在簡略的String變量中應用三個單引號。
假如你須要寫正則表達式,你必需應用斜槓字符標志:
assert"foooo/baaaaar"==~ /fo+\/ba+r/
斜槓標志的利益是,你不須要寫兩個反斜槓去做本義,讓正則表達式更簡練。
最初但並不是不主要,請應用單引號去界說字符常量,應用雙引號界說須要應用插值函數的字符串。
原生的數據構造語法
Groovy對數據構造供給原生語法,例如列表,映照,正則表達式或許一個規模內的數值。請在你的Groovy法式中好好應用它們。
以下是一些例子是應用那些原生數據構造的:
def list = [1,4,6,9] // 默許情形下,鍵是字符的,所以沒需要用引號括著它們 // 你可使用with()包括著鍵,例如應用[(狀況變量):狀況名],應用變量或對象作為鍵 def map = [CA:'California', MI:'Michigan'] def range =10..20 def pattern = ~/fo*/ // 同等於 add() list <<5 // 挪用 contains() assert4in list assert5in list assert15in range // 下標符號 assertlist[1] ==4 // 增長鍵值對 map << [WA:'Washington'] // 下標符號 assertmap['CA'] =='California' // 屬性 assertmap.WA =='Washington' // 應用正則表達式婚配字符串 assert'foo'=~ pattern
Grovvy 開辟對象
我們來持續說說數據構造,當你須要迭代聚集,Groovy供給異常豐碩的辦法,裝潢java的焦點數據構造,例如each{}, find{}, findAll{}, every{}, collect{}, inject{}.這些辦法給編程說話增長了些樂趣,同時贊助我們更輕松的設計龐雜的算法。經由過程裝潢器,年夜量的新辦法已運用於java的各類類型,這得得益於說話得的的靜態特征。你可以查找更多的應用在字符串,文件,流,聚集或許其他的辦法:
http://groovy.codehaus.org/groovy-jdk/
switch的力氣
Groovy的switch比C說話家族的更壯大,由於它們平日只吸收根本數據類型和。而Groovy的switch可以接收豐碩的數據類型:
def x =1.23 def result ="" switch(x) { case"foo": result ="found foo" // lets fall through case"bar": result +="bar" case[4,5,6,'in List']: result ="list" break case 12..30: result ="range" break case Integer: result ="integer" break case Number: result ="number" break default: result ="default" } assert result =="number"
平日情形,應用isCase()辦法可以斷定一個數值能否為年夜小寫。
別號導入 Import aliasing
Java,中當要應用來自兩個分歧包的同名class時,如
java.util.List 和 java.awt.List, 你能導入個中的一個類,而另外一個你就不能不給其有用的重定名了.
還有時刻我們在代碼中常常應用一個名字異常長的類,使得全部代碼變得癡肥不勝.
為了改良這些狀態, Groovy 供給了別號導入的特征:
importjava.util.List as juList importjava.awt.List as aList
importjava.awt.WindowConstants as WC //import的時刻 用 as 設置一個體名
固然也能夠靜態的導入某個辦法:
import static pkg.SomeClass.foo foo()
Groovy 的真值系統
在groovy中一切對象都可以被強迫轉為為一個boolean值,即: null, void 或空值 都 會視為 false, 其他的都視為 true.
所以不要再寫 這類代碼了:if (name != null && name.length > 0) {} 改成: if (name) {}
關於聚集和其他數據類型異樣實用.
是以,你可以在 諸如while(), if(), 三目運算符,Elvis 運算符(上面會講)等等的斷定前提中應用這類簡略的方法.
更強悍的是可以給你的 類 添加 asBoolean() 辦法,從而定制你這個類的真值的。
平安的操尴尬刁難象圖(嵌套的對象) Safe graph navigation
Groovy支撐應用 . 操作符來平安的操作一個對象圖.
Java中假如你對一個對象圖中的某個節點感興致,想檢討其能否為null的時刻,常常會寫出龐雜的if嵌代碼,以下:
if(order !=null) { //1 if(order.getCustomer() !=null) { //2 if(order.getCustomer().getAddress() !=null) { //3 System.out.println(order.getCustomer().getAddress()); } } }
而應用Groovy的平安操作符 ?. 可以講上述代碼簡化為:
println order?.customer?.address
太精巧了。
操作連上 每一個?.操作符後面的元素都邑做Null檢討,假如為null則拋出 NullPointerException 而且前往 一個 null值
斷言 Assert
要檢討參數、前往值等,你可使用 assert 語句。
和 Java 的 assert 比較,Groovy 的 assert 無需零丁激活。
def check(String name) { // name non-null and non-empty according to Groovy Truth assertname // safe navigation + Groovy Truth to check assertname?.size() >3 }
你將留意到 Groovy 的 Power Assert 語句供給更好的輸入,包含每一個子表達式斷言時分歧值的圖形化視圖。
Elvis (埃爾維斯) ?: 操作符給變量賦默許值
?: 是一個異常便利的給變量 賦 默許值的操作符,他是三目運算符(xx? a:b)的簡寫.
我們常常寫以下三目運算代碼:
def result = name !=null? name :"Unknown"//假如name為null時給'Unknown'的默許值,不然用原name的值
感激Groovy的真值系統,null的檢討可簡略直接的經由過程 ‘name'來斷定,null 會被轉成 false.
再深刻一點,既然總得前往'name',那在三目操作運算符中反復輸出name兩次就顯得包袱了,可以將問號和冒號之間輸出的反復變量移除,因而就成了Elvis操作符,以下:
def result = name ?:"Unknown" //假如斷定name為 false 則取 "Unknown",不然 取name之值<span></span>
捕獲任何異常
假如你真的不在意在一個try代碼塊中拋出的異常,groovy中可以簡略的catch一切這些異常,並疏忽其異常類型. 所以今後像這類捕獲異常的代碼:
try{ // ... }catch(Throwable t) { // something bad happens }
可以寫成捕獲隨意率性異常 ('any' or 'all', 或許其他你以為是"隨意率性"的單詞):
try{ // ... }catch(any) { // something bad happens }
可選類型 建議
最初我將評論辯論一下什麼時候和如何應用 '可選類型' 這個特征.
Groovy讓你本身來決議是 顯示應用強類型 照樣 應用def 症結字 來聲名你要的器械,那末怎樣決議呢?
我有個相當簡略的經歷軌則:
當你寫的代碼將會被作為公共API給他人應用時,你應該老是應用強類型的聲名。
這將使得: 接口商定加倍明白,防止能夠的毛病類型參數的傳遞,有益於供給更容易讀的文檔,在編纂如:僅你能應用的公有辦法時,強迫類型 會有益於IDE的代碼主動完勝利能,或使IDE更輕易揣摸對象的類型,然後你就可以加倍自若的決議能否應用明白的類型了