1、groovy是什麼java
簡單地說,Groovy 是下一代的java語言,跟java同樣,它也運行在 JVM 中。程序員
做爲跑在JVM中的另外一種語言,groovy語法與 Java 語言的語法很類似。同時,Groovy 拋棄了java煩瑣的文法。一樣的語句,使用groovy能在最大限度上減小你的擊鍵次數——這確實是「懶惰程序員們」的福音。閉包
2、開發環境eclipse
一、 jdk 1.5以上jvm
二、 eclipse+groovy plugin(支持Groovy 1.5.7)ide
打開eclipse,經過Software Updates > Find and Install...菜單,使用「Search for new features to install」 下載並安裝groovy插件。New一個遠程站點,url可以使用http://dist.codehaus.org/groovy/distributions/update/,插件名:Groovy plug-in。根據須要你能夠同時選擇groovy和grails(後續會學習到):函數
3、建立groovy項目
一、新建一個groovy項目
File--> New Project..建立一個java項目。爲了方便管理,建議在source中建兩個source文件夾java和groovy,
分別用於存儲java源文件和groovy源文件:
二、添加 Groovy 特性
在項目上右擊,Groovy Add Groovy Nature,這樣會在項目中添加 Groovy Libraries。
三、添加 Groovy 類
在項目groovy源文件下右鍵,New Other Groovy Groovy Class單元測試
自動生成的源代碼以下:
public class HelloWorld{
public static void main(def args){
// TODO Auto-generated method stub
}
}
咱們在main方法中加一句打印語句:
println "Hello World"學習
四、編譯運行groovy類
在源文件上右鍵,Compile Groovy File,而後右鍵,Run As à Groovy ,在控制檯中查看運行結果。
實際上 groovy 語法的簡練還體如今,就算整個文件中只有println "Hello World"這一句代碼(把除這一句之外的語句刪除掉吧),程序也照樣可以運行。
固然,爲了說明groovy 其實就是java,你也能夠徹底按照java 語法來編寫HelloWorld類。
4、Groovy語法簡介
一、沒有類型的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。測試
二、 不須要的public
你能夠把main方法前面的public去掉,實際上,groovy中默認的修飾符就是public,因此public修飾符你根本就不須要寫,這點跟java不同。
三、 不須要的語句結束符
Groovy中沒有語句結束符,固然爲了與java保持一致性,你也可使用;號做爲語句結束符。在前面的每一句代碼後面加上;號結束,程序一樣正常運行(爲了接受java程序員的頑固習慣)。
四、 字符串鏈接符
跟java同樣,若是你須要把一個字符串寫在多行裏,可使用+號鏈接字符串。代碼能夠這樣寫:
def var="hello "+
"world"+
",groovy!"
固然更groovy的寫法是:
def var="""hello
world
groovy!"""
三個」號之間不在須要+號進行鏈接(不過字符串中的格式符都會被保留,包括回車和tab)。
五、一切皆對象
聽起來象是「衆平生等」的味道,事實上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。
六、循環
刪除整個源文件內容,用如下代碼替代:
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)
這樣的結果是同樣的。
七、String 和 Gstring
除了標準的java.lang.String之外(用’號括住),groovy還支持Gstring字符串類型(用「號括住)。把上面的for循環中的語句改爲:
println "This is ${i}:${val}"
運行一下,你就會明白什麼是Gstring。
def name="Tom"
println "Myname is ${"John"+name}"
輸出:
Myname is JohnTom
def name="Tom"
println "Myname is ${"Tom"==name}"
輸出:
Myname is true
八、範圍
這個跟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循環中使用。
九、默認參數值
能夠爲方法指定默認參數值。咱們修改repeat方法的定義:
def repeat(val,repeat=3){
for(i in 0..<repeat){
println "This is ${i}:${val}"
}
}
能夠看到,repeat方法增長了一個參數repeat(而且給了一個默認值3),用於指定循環次數。
當咱們不指定第2個參數調用repeat方法時,repeat參數取默認值3。
十、集合
Groovy支持最多見的兩個java集合:java.util.Collection和java.util.Map。
前面所說的範圍實際也是集合的一種(java.util.List)。
(1)Collection
d={println "Size:${it.size}.Last Element:${it[-1]},Last Second Element:${it[-2]}"} c=["idx0","idx1","idx2"] d c //使用add往集合中添加元素 c.add(1) println c d c //使用<<往集合中添加元素 c<<"come on" println c d c println c //使用+往集合中添加元素 c=c+5 println c d c //在集合中減去元素idx1 c=c-'idx1' println c //把集合中的前3個元素去掉 c=c-c[0..2] println c
Output:
groovy> d={println "Size:${it.size}.Last Element:${it[-1]},Last Second Element:${it[-2]}"} groovy> c=["idx0","idx1","idx2"] groovy> d c groovy> //使用add往集合中添加元素 groovy> c.add(1) groovy> println c groovy> d c groovy> //使用<<往集合中添加元素 groovy> c<<"come on" groovy> println c groovy> d c groovy> println c groovy> //使用+往集合中添加元素 groovy> c=c+5 groovy> println c groovy> d c groovy> //在集合中減去元素idx1 groovy> c=c-'idx1' groovy> println c groovy> //把集合中的前3個元素去掉 groovy> c=c-c[0..2] groovy> println c Size:3.Last Element:idx2,Last Second Element:idx1 [idx0, idx1, idx2, 1] Size:4.Last Element:1,Last Second Element:idx2 [idx0, idx1, idx2, 1, come on] Size:5.Last Element:come on,Last Second Element:1 [idx0, idx1, idx2, 1, come on] [idx0, idx1, idx2, 1, come on, 5] Size:6.Last Element:5,Last Second Element:come on [idx0, idx2, 1, come on, 5] [come on, 5]
(2) Map
Map是「鍵-值」對的集合,在groovy中,鍵不必定是String,能夠是任何對象(實際上Groovy中的Map就是java.util.LinkedHashMap)。
如此能夠定義一個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做爲成員名索引
十一、閉包(Closure)
閉包是Groovy中很是重要的一個數據類型或者說一種概念。
閉包是一種數據類型,它表明了一段可執行的代碼。
簡而言之,Closure的定義格式是:
(1)有參數:
def 閉包名={
parameters->code
}
(2)無參數(不須要->符號)
def 閉包名={code}
若是閉包沒有定義參數的話,則隱含有一個參數,這個參數名字叫it,和this的做用相似。it表明閉包的參數
def 閉包名={
it->code
}
某種意義上,從C/C++語言的角度看,閉包和函數指針很像。閉包定義好後,要調用它的方法就是:
(1)閉包名.call(參數)
(2)閉包名(參數)
閉包是用{符號括起來的代碼塊,它能夠被單獨運行或調用,也能夠被命名。相似‘匿名類’或內聯函數的概念。
閉包中最多見的應用是對集合進行迭代,下面定義了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中沒有指針)。其次,閉包也能夠不命名(固然做爲代價,只能在定義閉包時執行一次),而方法不能夠。
十二、類
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 默認返回方法的最後一行的值。
1三、?運算符
在java中,有時候爲了不出現空指針異常,咱們一般須要這樣的技巧:
if(rs!=null){
rs.next()
… …
}
在groovy中,可使用?操做符達到一樣的目的:
rs?.next()
?在這裏是一個條件運算符,若是?前面的對象非null,執行後面的方法,不然什麼也不作。
1四、可變參數
等同於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)
1五、枚舉
定義一個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()
1六、Elvis操做符
這是三目運算符「?:」的簡單形式,三目運算符一般以這種形式出現:
String displayName = name != null ? name : "Unknown";
在groovy中,也能夠簡化爲(由於null在groovy中能夠轉化爲布爾值false):
String displayName = name ? name : "Unknown";
基於「不重複」的原則,可使用elvis操做符再次簡化爲:
String displayName = name ?: "Unknown"
1七、動態性
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()
}
1八、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程序很象?
5、單元測試
一、添加junit
使用 Build Path-->Libraries-->Add Library-->JUnit 把junit添加到項目中。
二、新建測試 使用 New a Junit Test Case
新建測試例程: PersonTest,
在Class under test右邊的Browser按鈕,選擇要進行測試的groovy類Person。
下面編寫測試用例代碼(我使用了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經過測試。
三、使用groovy書寫測試用例
除了使用Java來書寫測試用例之外,咱們也可使用groovy書寫。
寫一個類GroovyTestPerson:
import org.junit.*;
class GroovyTestPerson {
@Test
void testToString(){
Person p=new Person("name":"ddd","age":18)
Assert.assertEquals("ddd-18", p.toString())
}
}
能夠看到,這裏使用的徹底是Groovy風格的書寫方式:不須要public,使用map參數構造對象。然而當你Run AsàJunit Test的時候,結果跟用java編寫的測試用例沒有什麼兩樣。
這也充分說明了,groovy和java,除了語法不同,本質上沒有什麼區別(對比.net framework中的C#和VB.net,它們除了語法不一樣外,本質上它們都使用CLR)。
http://blog.csdn.net/kmyhy/article/details/4200563
collect和each的區別:
c=[1,2,3,7,5,6] println c.collect {print " ${it*it} "} println c.collect {"result:${it*it}"} println "=================" println c.each {print " ${it*it} " } p={k,v->println k+"="+v} c=["r":"red","b":"blue","y":"yellow"] e=c.each(p) println "=================" assert e==c d=c.collect p println "=================" assert d==[null,null,null] assert d==[null,null,"g"]
Output:
groovy> c=[1,2,3,7,5,6] groovy> println c.collect {print " ${it*it} "} groovy> println c.collect {"result:${it*it}"} groovy> println "=================" groovy> println c.each {print " ${it*it} " } groovy> p={k,v->println k+"="+v} groovy> c=["r":"red","b":"blue","y":"yellow"] groovy> e=c.each(p) groovy> println "=================" groovy> assert e==c groovy> d=c.collect p groovy> println "=================" groovy> assert d==[null,null,null] groovy> assert d==[null,null,"g"] 1 4 9 49 25 36 [null, null, null, null, null, null] [result:1, result:4, result:9, result:49, result:25, result:36] ================= 1 4 9 49 25 36 [1, 2, 3, 7, 5, 6] r=red b=blue y=yellow ================= r=red b=blue y=yellow ================= Exception thrown Assertion failed: assert d==[null,null,"g"] || |false [null, null, null] at ConsoleScript1.run(ConsoleScript1:17)
class Main { static void main(def args) { /** * NPE operator ?. */ def people = [null, new Person(name: "Gweneth")] for (Person person : people) { println "Valid person:${person?.name}" } /** * ==,equals,is */ Integer x = new Integer(2) Integer y = new Integer(2) Integer z = null if (x == y) println "x==y:${x == y}" if (!x.is(y)) println("x is not y:${x.is(y)}") if (z.is(null)) println "z is null:${z.is(null)}" if (z == null) println "z is null:${z == null}" /** * Process List Construct */ def jvmLanguages = ["Java", "Groovy", "Scala", "Clojure"] println "Output List:$jvmLanguages" println "Output index 0:${jvmLanguages[0]}" println(jvmLanguages.size()) println "Output list with range:${jvmLanguages[0..2]}" println "Output list with -1 index:${jvmLanguages[-1]}" jvmLanguages = [] println(jvmLanguages) /** * Process map construct */ def languageRatings = [Java: 100, Groovy: 99, Clojure: "N/A"] println "Output map construct with key:${languageRatings["Java"]}" println "Output with .:${languageRatings.Clojure}" languageRatings["Clojure"] = 75 println "Output new value:${languageRatings["Clojure"]}" languageRatings.Java = "100Java" println "Output new value:${languageRatings["Java"]}" languageRatings = [:] println languageRatings /** * For Number process */ println 3 + 0.2 /** * Process xml */ def writer = new StringWriter(); def xml = new groovy.xml.MarkupBuilder(writer); xml.person(id: 2) { name 'Gweneth' age 1 } println writer.toString() /** * for Hello */ println "Hello!" /** * lamba */ def sayHello = { name -> if (name == "Tom") println "Hello author:$name" else println "Hello reader:$name" } println "Lamba:${sayHello("Tom")}" println "Lamba:${sayHello("Jack")}" /** * Lamba used by Collection */ def movieTitles=["Seven","SnowWhite","Die Hard"] movieTitles.each {movieTitle->println movieTitle} movieTitles.each {movieTitle->println "Seven"==movieTitle } movieTitles.each {movieTitle->println "Result:${"Seven"==movieTitle}" } movieTitles.each {println it } movieTitles.each {println "Seven"==it } movieTitles.each {println "Result:${"Seven"==it}" } /** * regex */ def pattern=/1010/ def input="1010" def matcher=input=~pattern if (input==~pattern){ input=matcher.replaceFirst("0101") println input } ("Hazel 1"=~/(\w+) (\d+)/).each {full,name,age->println "$name is $age years old"} } } class Person{ def name; }
Output:
Valid person:null Valid person:Gweneth x==y:true x is not y:false z is null:true z is null:true Output List:[Java, Groovy, Scala, Clojure] Output index 0:Java 4 Output list with range:[Java, Groovy, Scala] Output list with -1 index:Clojure [] Output map construct with key:100 Output with .:N/A Output new value:75 Output new value:100Java [:] 3.2 <person id='2'> <name>Gweneth</name> <age>1</age> </person> Hello! Hello author:Tom Lamba:null Hello reader:Jack Lamba:null Seven SnowWhite Die Hard true false false Result:true Result:false Result:false Seven SnowWhite Die Hard true false false Result:true Result:false Result:false 0101 Hazel is 1 years old
xml_content= """ <langs type="current"> <language>Java</language> <language>Groovy</language> <language>JavaScript</language> </langs> """ xml=new XmlParser().parseText(xml_content) xml.language.eachWithIndex { it,idx-> println "$idx: ${it.text()}" }
Output:
groovy> xml_content= groovy> """ groovy> <langs type="current"> groovy> <language>Java</language> groovy> <language>Groovy</language> groovy> <language>JavaScript</language> groovy> </langs> groovy> """ groovy> xml=new XmlParser().parseText(xml_content) groovy> xml.language.eachWithIndex { groovy> it,idx-> groovy> println "$idx: ${it.text()}" groovy> } 0: Java 1: Groovy 2: JavaScript Result: [language[attributes={}; value=[Java]], language[attributes={}; value=[Groovy]], language[attributes={}; value=[JavaScript]]]