Groovy常見語法匯總


 一、groovy是什么

簡單地說,Groovy 是下一代的java語言,跟java一樣,它也運行在 JVM 中。

作為跑在JVM中的另一種語言,groovy語法與 Java 語言的語法很相似。同時,Groovy 拋棄了java煩瑣的文法。同樣的語句,使用groovy能在最大限度上減少你的擊鍵次數——這確實是“懶惰程序員們”的福音。

二、開發環境

1、  jdk 1.5以上

2、  eclipse+groovy plugin(支持Groovy 1.5.7)

打開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(后續會學習到):

三、創建groovy項目
1、新建一個groovy項目
File--> New Project..創建一個java項目。為了方便管理,建議在source中建兩個source文件夾java和groovy,
分別用於存儲java源文件和groovy源文件:
2、添加 Groovy 特性
在項目上右擊,Groovy  Add Groovy Nature,這樣會在項目中添加 Groovy Libraries。
3、添加 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"

4、編譯運行groovy類
在源文件上右鍵,Compile Groovy File,然后右鍵,Run As à Groovy ,在控制台中查看運行結果。
實際上 groovy 語法的簡練還體現在,就算整個文件中只有println "Hello World"這一句代碼(把除這一句以外的語句刪除掉吧),程序也照樣能夠運行。
當然,為了說明groovy 其實就是java,你也可以完全按照java 語法來編寫HelloWorld類。

四、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。

def name="Tom"
println "Myname is ${"John"+name}"

輸出:

Myname is JohnTom

 

def name="Tom"
println "Myname is ${"Tom"==name}"

輸出:

Myname is true



8、范圍

這個跟pascal中的“子界”是一樣的。在前面的for循環介紹中我們已經使用過的for(i in 0..5)這樣的用法,其中的0..5就是一個范圍。

范圍 是一系列的值。例如 “0..4” 表明包含 整數 0、1、2、3、4。Groovy 還支持排除范圍,“0..<4” 表示 0、1、2、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

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作為成員名索引

11、閉包(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中沒有指針)。其次,閉包也可以不命名(當然作為代價,只能在定義閉包時執行一次),而方法不可以。

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-->Libraries-->Add Library-->JUnit 把junit添加到項目中。
2、新建測試 使用 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通過測試。


3、使用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]]]

http://kldn.iteye.com/blog/1279540 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM