- 沒有類型的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!"
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]
println collect[-1] //索引其倒數第1個元素
println collect[-2] //索引其倒數第2個元素
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中沒有指針)。
- 其次,閉包也可以不命名(當然作為代價,只能在定義閉包時執行一次),而方法不可以。
- 類
/*下面看一個完整類定義的例子:*/
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程序很象?