Groovy讀書筆記

groovy是什么

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

開發環境

  • jdk 1.5以上
  • eclipse+groovy plugin(支持Groovy 1.5.7)
  • ==待補充//TUDO==

創建groovy項目

  • 新建一個groovy項目
    • New --> Project Java 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{
    /**
     * @param args
        */
        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類。

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。
    
  • 范圍
    • 這個跟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循環中使用。
  • 默認參數值
    • 可以為方法指定默認參數值。我們修改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)。
    • 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] //也可以用負索引,證明最后一個元素就是第一個元素
      
    • Map
      • Map是“鍵-值”對的集合,在groovy中,鍵不一定是String,可以是任何對象(實際上Groovy中的Map就是java.util.Linke dHashMap)。
      • 如此可以定義一個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)
    • 閉包是用{符號括起來的代碼塊,它可以被單獨運行或調用,也可以被命名。類似‘匿名類’或內聯函數的概念.
    • 閉包中最常見的應用是對集合進行迭代,下面定義了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代碼
    • 不需要public修飾符
      • 如前面所言,groovy的默認訪問修飾符就是public,如果你的groovy類成員需要public修飾,則你根本不用寫它。
    • 不需要類型說明
      • 同樣前面也說過,groovy也不關心變量和方法參數的具體類型
    • 不需要getter/setter方法
      • 不要奇怪,在很多ide(如eclipse)早就可以為序員自動產生getter/setter方法了。
      • 在groovy中,則徹底不需要getter/setter方法——所有類成員(如果是默認的public)根本不用通過getter/setter方法引用它們(當然,如果你一定要通過get/set方法訪問成員屬性,groovy也提供了它們)。
    • 不需要構造函數
      • 不在需要程序員聲明任何構造函數,因為groovy自動提供了足夠你使用的構造函數。
      • 不用擔心構造函數不夠多,因為實際上只需要兩個構造函數(1個不帶參數的默認構造函數,1個只帶一個map參數的構造函數—由于是map類型,通過這個參數你可以在構造對象時任意初始化它的成員變量)。
    • 不需要return
      • Groovy中,方法不需要return來返回值嗎?這個似乎很難理解。看后面的代碼吧。
      • 因此,groovy風格的類是這樣的:==//TUDO==
    • 不需要()號
      • 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
    
    /*
    注意:
    1.這樣需要注意我們覆蓋了Object的toString方法,因為我們想通過println person1這樣的方法簡單地打印對象的屬性值。
    2.然而toString 方法中并沒有return 一個String,但不用擔心,Groovy 默認返回方法的最后一行的值。
    */
    
  • ?運算符
    • 在java中,有時候為了避免出現空指針異常,我們通常需要這樣的技巧:
    if(rs!=null){
        rs.next()
        … …
    }
    
    • 在groovy中,可以使用?操作符達到同樣的目的:
    rs?.next()
    
    • ?在這里是一個條件運算符,如果?前面的對象非null,執行后面的方法,否則什么也不做。
  • 可變參數
    • 等同于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)
    
  • 枚舉
    //定義一個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()
    
  • Elvis操作符
    //這是三目運算符“?:”的簡單形式,三目運算符通常以這種形式出現:
    String displayName = name != null ? name : "Unknown";
    
    //在groovy中,也可以簡化為(因為null在groovy中可以轉化為布爾值false):
    String displayName = name ? name : "Unknown";
    
    //基于“不重復”的原則,可以使用elvis操作符再次簡化為:
    String displayName = name ?: "Unknown"
    
  • 動態性
    /**
    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()
    }
    
  • 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程序很象?
    

單元測試

  • 添加junit
    • 使用 Build Path?Add Libraries...把junit添加到項目中。
  • 新建測試
    • 使用 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通過測試。
    
    • 使用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())
        }
    }
    
    /**
    可以看到,這里使用的完全是Groovy風格的書寫方式:
    不需要public,使用map參數構造對象。
    然而當你Run As?Junit Test的時候,結果跟用java編寫的測試用例沒有什么兩樣。
    這也充分說明了,groovy和java,除了語法不一樣,本質上沒有什么區
    (對比.net framework中的C#和VB.NET,它們除了語法不同外,本質上它們都使用CLR)。
    */
    
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,786評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,656評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,697評論 0 379
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,098評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,855評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,254評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,322評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,473評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,014評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,833評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,016評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,568評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,273評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,680評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,946評論 1 288
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,730評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,006評論 2 374

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,787評論 18 139
  • //Clojure入門教程: Clojure – Functional Programming for the J...
    葡萄喃喃囈語閱讀 3,713評論 0 7
  • 什么是 Groovy? 簡言之,Groovy是一種基于JVM(Java虛擬機)的敏捷動態開發語言。它是一種成熟的面...
    北緯26閱讀 4,146評論 0 14
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,722評論 18 399
  • 曾看到一句話:念舊的人活的就像個拾荒者。 以前,我不是很明白這話的意思。念舊的人怎么可以怎么能跟拾荒者做比較...
    和半熟閱讀 17,987評論 3 4