簡介
Groovy 是 用於Java虛擬機的一種敏捷的動態語言,它是一種成熟的面向對象編程語言,既能夠用於面向對象編程,又能夠用做純粹的腳本語言。使用該種語言沒必要編寫過多的代碼,同時又具備閉包和動態語言中的其餘特性。
Groovy是JVM的一個替代語言(替代是指能夠用 Groovy 在Java平臺上進行 Java 編程),使用方式基本與使用 Java代碼的方式相同,該語言特別適合與Spring的動態語言支持一塊兒使用,設計時充分考慮了Java集成,這使 Groovy 與 Java 代碼的互操做很容易。(注意:不是指Groovy替代java,而是指Groovy和java很好的結合編程。
基本特色
二、爲Java開發者提供了 現代最流行的編程語言特性,並且學習成本很低(幾乎爲零)。
四、受檢查類型異常(Checked Exception)也能夠不用捕獲。
五、 Groovy擁有處理原生類型,面向對象以及一個Ant DSL,使得建立Shell Scripts變得很是簡單。
七、支持單元測試和模擬(對象),能夠 簡化測試。
八、無縫集成 全部已經存在的 Java對象和類庫。
九、直接編譯成Java字節碼,這樣能夠在任何使用Java的地方 使用Groovy。[2]
十一、一些新的運算符。
十二、默認導入經常使用的包。
1三、斷言不支持jvm的-ea參數進行開關。
1四、支持對對象進行布爾求值。
1六、groovy中基本類型也是對象,能夠直接調用對象的方法。java 類型對於變量,屬性,方法,閉包的參數以及方法的返回類型都是無關緊要的,都是在給變量賦值的時候才決定它的類型, 不一樣的類型會在後面用到,任何類型均可以被使用,即便是基本類型 (經過自動包裝(autoboxing)). 當須要時,不少類型之間的轉換都會自動發生,好比在這些類型之間的轉換: 字符串(String),基本類型(如int) 和類型的包裝類 (如Integer)之間,能夠把不一樣的基本類型添加到同一數組(collections)中。web 閉包就是可使用參數的代碼片斷,每一個閉包會被編譯成繼承groovy.lang.Closure類的類,這個類有一個叫call方法,經過該方法能夠傳遞參數並調用這個閉包.它們能夠訪問並修改在閉包建立的範圍內的變量,在閉包內建立的變量在閉包被調用的範圍內一樣能夠被引用, 閉包能夠保存在變量中並被做爲參數傳遞到方法中。編程 語法數組 Groovy 語法與Java 語言的語法很類似,雖然 Groovy 的語法源於Smalltalk和Ruby這類語言的理念,可是能夠將它想像成 Java 語言的一種更加簡單、表達能力更強的變體。(在這點上,Ruby與 Groovy 不一樣,由於它的語法與 Java 語法差別很大。)閉包 許多 Java 開發人員喜歡 Groovy 代碼和 Java 代碼的類似性。從學習的角度看,若是知道如何編寫 Java 代碼,那就已經瞭解 Groovy 了。Groovy 和 Java 語言的主要區別是:完成一樣的任務所需的 Groovy 代碼比 Java 代碼更少。框架 類eclipse Groovy類和java類同樣,徹底能夠用標準java bean的語法定義一個Groovy類。但做爲另外一種語言,可使用更Groovy的方式定義類,這樣的好處是,能夠少寫一半以上的javabean代碼。jvm (1)不需public修飾符 如前面所言,Groovy的默認訪問修飾符就是public,若是Groovy類成員須要public修飾,則根本不用寫它。 (2)不須要類型說明 一樣前面也說過,Groovy也不關心變量和方法參數的具體類型。 (3)不須要getter/setter方法 在不少ide(如eclipse)早就能夠爲程序員自動產生getter/setter方法了,在Groovy中,不須要getter/setter方法--全部類成員(若是是默認的public)根本不用經過getter/setter方法引用它們(固然,若是必定要經過getter/setter方法訪問成員屬性,Groovy也提供了它們)。 (4)不須要構造函數 再也不須要程序員聲明任何構造函數,由於實際上只須要兩個構造函數(1個不帶參數的默認構造函數,1個只帶一個map參數的構造函數--因爲是map類型,經過這個參數能夠構造對象時任意初始化它的成員變量)。 (5)不須要return Groovy中,方法不須要return來返回值。 (6)不須要() Groovy中方法調用能夠省略()(構造函數除外)。 文件與類的關係
在Groovy中類和文件的對應關係並不像Java中那麼固定(Java中一個文件只能有一個聲明爲public的類和其餘一些非公共的類和內嵌類) 。在同一個groovy文件中能夠包含多個public的類定義。具體規則以下:
若是在一個groovy文件中沒有任何類定義,它將被當作script來處理,也就意味着這個文件將被透明的轉換爲一個Script類型的類,這個自動轉換獲得的類將使用原始的groovy文件名(去掉擴展名,沒有包名,在default包中)做爲類的名字。groovy文件的內容被打包進run方法,另外在新產生的類中被加入一個main方法以進行外部執行該腳本。
若是在groovy文件正好有一個類的定義,而且該類的名字與文件名稱相同,那麼這就和java中的類與文件的一一對應關係相同。
在一個groovy文件中能夠包含多個不一樣可見性的類定義,而且沒有強制性的要求其中有一個類的類名與文件名相同。groovyc編譯器會很樂於把該文件中定義的全部的類都編譯成*.class文件。若是但願可以直接調用這個groovy script,好比說在使用groovy命令行或者在某個IDE中執行,那麼應該在該文件中的第一個類中定義一個main方法。
在一個groovy文件中能夠混合類的定義和腳本定義。在這種狀況下,那些腳本代碼將會變成直接調用的主類,因此在這種狀況下不該該再定義一個和文件同名的類。
在沒有通過明確的編譯過程即執行時,groovy將經過文件名來查找類。在這種狀況下,名稱將會很重要。Groovy只能找到那些和文件名匹配的類。在找到這種名字匹配的類時,找到的文件中定義的其餘類將被解析並變得對groovy可見。
安裝 groovy eclipse 插件 6.試在 eclipse 裏寫下 groovy 腳本。在 src 下新建 hello.groovy 文件,輸入如:println "Hello World!" 7.點運行的圖標...(在源文件上右鍵,Compile Groovy File,而後右鍵,Run As --- Groovy ,在控制檯中查看運行結果。) Groovy語法簡介 1.沒有類型的java 做爲動態語言,groovy中全部的變量都是對象(相似於.net framework,全部對象繼承自java.lang.Object),在聲明一個變量時,groovy不要求強制類型聲明,僅僅要求變量名前使用關鍵字def(從groovy jsr 1開始,在之前的版本中,甚至連def都不須要)。 修改main 方法中的代碼: def var="hello world" println var println var.class 你能夠看到程序最後輸出了var的實際類型爲:java.lang.String 做爲例外,方法參數和循環變量的聲明不須要def。 2.不須要的public 你能夠把main方法前面的public去掉,實際上,groovy中默認的修飾符就是public,因此public修飾符你根本就不須要寫,這點跟java不同。 3.不須要的語句結束符 Groovy中沒有語句結束符,固然爲了與java保持一致性,你也可使用;號做爲語句結束符。在前面的每一句代碼後面加上;號結束,程序一樣正常運行(爲了接受java程序員的頑固習慣)。 4.字符串鏈接符 跟java同樣,若是你須要把一個字符串寫在多行裏,可使用+號鏈接字符串。代碼能夠這樣寫: def var="hello "+ "world"+ ",groovy!" 固然更groovy的寫法是: def var="""hello world groovy!""" 三個」號之間不在須要+號進行鏈接(不過字符串中的格式符都會被保留,包括回車和tab)。 5. 一切皆對象 聽起來象是「衆平生等」的味道,事實上groovy對於對象是什麼類型並不關心,一個變量的類型在運行中隨時能夠改變,一切根據須要而定。若是你賦給它boolean ,那麼無論它原來是什麼類型,它接受boolean值以後就會自動把類型轉變爲boolean值。看下面的代碼: def var="hello "+ "world"+ ",groovy!" println var; println var.class; var=1001 println var.class 輸出結果: hello world,groovy! class java.lang.String class java.lang.Integer
var這個變量在程序運行中,類型在改變。一開始給它賦值String,它的類型就是String,後面給它賦值Integer,它又轉變爲Integer。 6.循環 刪除整個源文件內容,用如下代碼替代: def var="hello "+ "world"+ ",groovy!" def repeat(val){ for(i = 0; i < 5; i++){ println val } } repeat(var) 輸出: hello world,groovy! hello world,groovy! hello world,groovy! hello world,groovy! hello world,groovy! 注意循環變量i前面沒有def。固然也沒有java中常見的int,但若是你非要加上int也不會有錯,由於從Groovy1.1beta2以後開始(不包括1.1beta2),groovy開始支持java經典的for循環寫法。 此外,上面的for語句還能夠寫成: for(i in 0..5) 這樣的結果是同樣的。 7.String 和 Gstring 除了標準的java.lang.String之外(用’號括住),groovy還支持Gstring字符串類型(用「號括住)。把上面的for循環中的語句改爲: println "This is ${i}:${val}" 運行一下,你就會明白什麼是Gstring。 8.範圍 這個跟pascal中的「子界」是同樣的。在前面的for循環介紹中咱們已經使用過的for(i in 0..5)這樣的用法,其中的0..5就是一個範圍。 範圍 是一系列的值。例如 「0..4」 代表包含 整數 0、一、二、三、4。Groovy 還支持排除範圍,「0..<4」 表示 0、一、二、3。還能夠建立字符範圍:「a..e」 至關於 a、b、c、d、e。「a..<e」 包括小於 e 的全部值。 範圍主要在for循環中使用。 9. 默認參數值 能夠爲方法指定默認參數值。咱們修改repeat方法的定義: def repeat(val,repeat=3){ for(i in 0..<repeat){ println "This is ${i}:${val}" } } 能夠看到,repeat方法增長了一個參數repeat(而且給了一個默認值3),用於指定循環次數。 當咱們不指定第2個參數調用repeat方法時,repeat參數取默認值3。 10.集合 Groovy支持最多見的兩個java集合:java.util.Collection和java.util.Map。前面所說的範圍實際也是集合的一種(java.util.List)。 (1) Collection Groovy 中這樣來定義一個Collection: def collect=["a","b","c"] 除了聲明時往集合中添加元素外,還能夠用如下方式向集合中添加元素: collect.add(1); collect<<"come on"; collect[collect.size()]=100.0 Collection使用相似數組下標的方式進行檢索: println collect[collect.size()-1] println collect[5] groovy支持負索引: println collect[-1] //索引其倒數第1個元素 println collect[-2] //索引其倒數第2個元素 Collection支持集合運算: collect=collect+5 //在集合中添加元素5 println collect[collect.size()-1] collect=collect-'a' //在集合中減去元素a(第1個) println collect[0] //如今第1個元素變成b了 一樣地,你能夠往集合中添加另外一個集合或刪除一個集合: collect=collect-collect[0..4] //把集合中的前5個元素去掉 println collect[0] //如今集合中僅有一個元素,即原來的最後一個元素 println collect[-1] //也能夠用負索引,證實最後一個元素就是第一個元素 (2) Map Map是「鍵-值」對的集合,在groovy中,鍵不必定是String,能夠是任何對象(實際上Groovy中的Map就是java.util. 如此能夠定義一個Map: def map=['name':'john','age':14,'sex':'boy'] 添加項: map=map+['weight':25] //添加john的體重 map.put('length',1.27) //添加john的身高 map.father='Keller' //添加john的父親 能夠用兩種方式檢索值: println map['father'] //經過key做爲下標索引 println map.length //經過key做爲成員名索引 11.閉包(Closure) 閉包是用{符號括起來的代碼塊,它能夠被單獨運行或調用,也能夠被命名。相似‘匿名類’或內聯函數的概念。 閉包中最多見的應用是對集合進行迭代,下面定義了3個閉包對map進行了迭代: map.each({key,value-> //key,value兩個參數用於接受每一個元素的鍵/值 println "$key:$value"}) map.each{println it} //it是一個關鍵字,表明map集合的每一個元素 map.each({ println it.getKey()+"-->"+it.getValue()}) 除了用於迭代以外,閉包也能夠單獨定義: def say={word-> println "Hi,$word!" } 調用: say('groovy') say.call('groovy&grails') 輸出: Hi,groovy! Hi,groovy&grails!
看起來,閉包相似於方法,須要定義參數和要執行的語句,它也能夠經過名稱被調用。然而閉包對象(不要奇怪,閉包也是對象)能夠做爲參數傳遞(好比前面的閉包做爲參數傳遞給了map的each方法)。而在java中,要作到這一點並不容易(也許C++中的函數指針能夠,但不要忘記java中沒有指針)。其次,閉包也能夠不命名(固然做爲代價,只能在定義閉包時執行一次),而方法不能夠。 12.類 Groovy類和java類同樣,你徹底能夠用標準java bean的語法定義一個groovy 類。但做爲另外一種語言,咱們可使用更groovy的方式定義和使用類,這樣的好處是,你能夠少寫一半以上的javabean代碼: (1)不須要public修飾符 如前面所言,groovy的默認訪問修飾符就是public,若是你的groovy類成員須要public修飾,則你根本不用寫它。 (2)不須要類型說明 一樣前面也說過,groovy也不關心變量和方法參數的具體類型。 (3)不須要getter/setter方法 不要奇怪,在不少ide(如eclipse)早就能夠爲序員自動產生getter/setter方法了。在groovy中,則完全不須要getter/setter方法——全部類成員(若是是默認的public)根本不用經過getter/setter方法引用它們(固然,若是你必定要經過get/set方法訪問成員屬性,groovy也提供了它們)。 (4)不須要構造函數 不在須要程序員聲明任何構造函數,由於groovy自動提供了足夠你使用的構造函數。不用擔憂構造函數不夠多,由於實際上只須要兩個構造函數(1個不帶參數的默認構造函數,1個只帶一個map參數的構造函數—因爲是map類型,經過這個參數你能夠在構造對象時任意初始化它的成員變量)。 (5)不須要return Groovy中,方法不須要return來返回值嗎?這個彷佛很難理解。看後面的代碼吧。 所以,groovy風格的類是這樣的: (6)不須要()號 Groovy中方法調用能夠省略()號(構造函數除外),也就是說下面兩句是等同的: person1.setName 'kk'person1.setName('kk')下面看一個完整類定義的例子: class Person { def name def age String toString(){//注意方法的類型String,由於咱們要覆蓋的方法爲String類型 "$name,$age" } 若是你使用javabean風格來作一樣的事,起碼代碼量要增長1倍以上。 咱們可使用默認構造方法實例化Person類: def person1=new Person() person1.name='kk' person1.age=20 println person1 也能夠用groovy的風格作一樣的事: def person2=new Person(['name':'gg','age':22]) //[]號能夠省略 println person2 這樣須要注意咱們覆蓋了Object的toString方法,由於咱們想經過println person1這樣的方法簡單地打印對象的屬性值。 然而toString 方法中並無return 一個String,但不用擔憂,Groovy 默認返回方法的最後一行的值。 13.?運算符 在java中,有時候爲了不出現空指針異常,咱們一般須要這樣的技巧: if(rs!=null){ rs.next() … … } 在groovy中,可使用?操做符達到一樣的目的: rs?.next() ?在這裏是一個條件運算符,若是?前面的對象非null,執行後面的方法,不然什麼也不作。 14.可變參數 等同於java 5中的變長參數。首先咱們定義一個變長參數的方法sum: int sum(int... var) { def total = 0 for (i in var) total += i return total } 咱們能夠在調用sum時使用任意個數的參數(1個,2個,3個……): println sum(1) println sum(1,2) println sum(1,2,3) 15.枚舉 定義一個enum: enum Day { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY } 而後咱們在switch語句中使用他: def today = Day.SATURDAY switch (today) { //Saturday or Sunday case [Day.SATURDAY, Day.SUNDAY]: println "Weekends are cool" break //a day between Monday and Friday case Day.MONDAY..Day.FRIDAY: println "Boring work day" break default: println "Are you sure this is a valid day?" } 注意,switch和case中可使用任何對象,尤爲是能夠在case中使用List和範圍,從而使分支知足多個條件(這點跟delphi有點象)。 同java5同樣,groovy支持帶構造器、屬性和方法的enum: enum Planet { MERCURY(3.303e+23, 2.4397e6), VENUS(4.869e+24, 6.0518e6), EARTH(5.976e+24, 6.37814e6), MARS(6.421e+23, 3.3972e6), JUPITER(1.9e+27,7.1492e7), SATURN(5.688e+26, 6.0268e7), URANUS(8.686e+25, 2.5559e7), NEPTUNE(1.024e+26, 2.4746e7) double mass double radius Planet(double mass, double radius) { this.mass = mass; this.radius = radius; } void printMe() { println "${name()} has a mass of ${mass} " + "and a radius of ${radius}" } } Planet.EARTH.printMe() 16.Elvis操做符 這是三目運算符「?:」的簡單形式,三目運算符一般以這種形式出現: String displayName = name != null ? name : "Unknown"; 在groovy中,也能夠簡化爲(由於null在groovy中能夠轉化爲布爾值false): String displayName = name ? name : "Unknown"; 基於「不重複」的原則,可使用elvis操做符再次簡化爲: String displayName = name ?: "Unknown" 17.動態性 Groovy全部的對象都有一個元類metaClass,咱們能夠經過metaClass屬性訪問該元類。經過元類,能夠爲這個對象增長方法(在java中不可想象)!見下面的代碼,msg是一個String,經過元類,咱們爲msg增長了一個String 類中所沒有的方法up: def msg = "Hello!" println msg.metaClass String.metaClass.up = { delegate.toUpperCase() } println msg.up() 經過元類,咱們還能夠檢索對象所擁有的方法和屬性(就象反射): msg.metaClass.methods.each { println it.name } msg.metaClass.properties.each { println it.name } 甚至咱們能夠看到咱們剛纔添加的up方法。 咱們能夠經過元類判斷有沒有一個叫up的方法,而後再調用它: if (msg.metaClass.respondsTo(msg, 'up')) { println msg.toUpperCase() } 固然,也能夠推斷它有沒有一個叫bytes的屬性: if (msg.metaClass.hasProperty(msg, 'bytes')) { println msg.bytes.encodeBase64() } 18.Groovy swing 到如今爲止,咱們的groovy一直都在控制檯窗口下工做。若是你還不知足,固然也可使用swingbuilder來構建程序: import groovy.swing.SwingBuilder import java.awt.BorderLayout import groovy.swing.SwingBuilder import java.awt.BorderLayout as BL def swing = new SwingBuilder() count = 0 def textlabel def frame = swing.frame(title:'Frame', size:[300,300]) { borderLayout() textlabel = label(text:"Clicked ${count} time(s).", constraints: BL.NORTH) button(text:'Click Me', actionPerformed: {count++; textlabel.text = "Clicked ${count} time(s)."; println "clicked"}, constraints:BorderLayout.SOUTH) } frame.pack() frame.show() 怎麼樣?是否是跟java 中寫swing程序很象?
單元測試 1.添加junit 使用 Build PathàAdd Libraries... 把junit添加到項目中。 2.新建測試 使用 New à Junit Test Case 新建測試例程:PersonTest,在Class under test右邊的Browser按鈕,選擇要進行測試的groovy類Person。 Finish,下面編寫測試用例代碼(我使用了Junit4): import org.junit.*; public class TestPerson { @Test public void testToString(){ Person p=new Person(); //注意由於groovy編譯Person時默認全部屬性爲private p.setName("ddd"); //因此用set方法設置name屬性而不用p.name=」ddd」 p.setAge(18); Assert.assertEquals("ddd-18", p.toString()); } } 運行Run AsàJunit Test,發現testToString經過測試。 3.使用groovy書寫測試用例 除了使用Java來書寫測試用例之外,咱們也可使用groovy書寫。 New à Other à Groovy à Groovy Class,寫一個類GroovyTestPerson: import org.junit.*;
class GroovyTestPerson { @Test void testToString(){ Person p=new Person("name":"ddd","age":18) Assert.assertEquals("ddd-18", p.toString()) } } |