Groovy的語法入門

簡單地說,Groovy 是下一代的Java語言,跟java一樣,它也運行在 JVM 中。
作爲跑在JVM中的另一種語言,groovy語法與 Java 語言的語法很相似。同時,Groovy 拋棄了java煩瑣的語法。

聲明變量

作爲動態語言,groovy中所有的變量都是對象(類似於.net framework,所有對象繼承自java.lang.Object),在聲明一個變量時,groovy不要求強制類型聲明,僅僅要求變量名前使用關鍵字def(從groovy jsr 1開始,在以前的版本中,甚至連def都不需要)。

// 聲明一個變量
def var="hello world"
println var
println var.class

你可以看到程序最後輸出了var的實際類型爲:java.lang.String。

Note:方法參數和循環變量的聲明不需要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

循環

刪除整個源文件內容,用以下代碼替代:

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 printInfo(){
    ...
}

def f(){} 最後一行的爲返回值 不需要用return

範圍

這個跟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..

默認參數值

可以爲方法指定默認參數值。我們修改repeat方法的定義:

def repeat(val,repeat=3){
            for(i in 0..<repeat){
             println "This is ${i}:${val}"
            }
       }

可以看到,repeat方法增加了一個參數repeat(並且給了一個默認值3),用於指定循環次數。
當我們不指定第2個參數調用repeat方法時,repeat參數取默認值3。

集合

List

Groovy 中這樣來定義一個List:

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個元素

List支持集合運算:

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代碼:

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 默認返回方法的最後一行的值。

?運算符

在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()
}

文件

文件讀取(逐行讀取內容)

def readLine(fileName) {  
    new File(fileName).eachLine { line ->  
            println "Line: ${line}"  
    }  
}  

列出目錄所有文件(包含子文件夾,子文件夾內文件)

def printDir(dirName) {  
    def dir = new File(dirName)  
    if (dir.isDirectory()) {  
        dir.eachFileRecurse { file ->  
            println file  
        }  
    }  
}  

向文件中寫入內容

def writeFile(fileName) {  
    def file = new File(fileName)  

    if (file.exists())   
        file.delete()  

    def printWriter = file.newPrintWriter() //   

    printWriter.write('The first content of file')  
    printWriter.write('\n')  
    printWriter.write('The first content of file')  

    printWriter.flush()  
    printWriter.close()  
}

Json操作

創建一個json對象

def json = new JsonBuilder()
json.state{
   capital "Denver"
   majorCities "Denver", "Colorado Springs", "Fort Collins"
}

打印json

println JsonOutput.prettyPrint(json.toString())

輸出

{
    "state": {
        "capital": "Denver",
        "majorCities": [
            "Denver",
            "Colorado Springs",
            "Fort Collins"
        ]
    }
}

Json轉POJO

import groovy.json.JsonSlurper
def jsonPayload = new File("states.js").text
def slurper = new JsonSlurper()
def states = slurper.parseText(jsonPayload)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章