# alt.lang.jre: 感受 Groovy
_介紹 Java 平臺的一種新標準語言_
雖然 Java 語言因其嚴密性和擴展性的承諾而在整整一代程序員中勝出,但是 Groovy 預示了 Java 平臺上的一個編程新時代,這種語言是以方便性、適宜性和敏捷性為出發點定義的。在新的 _alt.lang.jre_專欄的第二期文章中,Andrew Glover 對提議添加到 Java 平臺的標準編程語言作了非正式的介紹。
如果您在使用 Java 平臺(block),不管時間長短,您都有可能聽說過 Groovy。Groovy 是超級明星開發人員 James Strachan 和 Bob McWhirter 發明的,它是一種敏捷開發語言,完全以 Java 編程 API 為基礎。Groovy 當前正處于 Java Specification Request 的開始階段,它于 2004 年 3 月底獲得批準。Groovy 還是一種腳本語言,有些人說它會永久性地改變您看待和使用 Java 平臺的方式。
在其對 JSR 241 (請參閱 [參考資料](#resources))的開放評論中,Groovy 的共同規范領導者 Richard Monson-Haefel 說他對 Groovy 的支持是建立在總有一天 Java 平臺要包括一種敏捷開發語言這一信念上。與許多移植到 Java 平臺的腳本語言不同,Groovy 是 _為_JRE 而寫的。在規范請求中(參閱 [參考資料](#resources)),Groovy 的制造者提出了“Java 不僅是一種編程語言,更是一個健壯的平臺,可以有多種語言在上面運行和共存”(Monson-Haefel 語)的思想。
新 _alt.lang.jre_專欄的這第二期文章的目的是讓讀者了解 Groovy。我首先回答關于這種新語言的一些最顯然的問題(為什么需要它?),然后以代碼為基礎概述 Groovy 最令人興奮的功能。
## 為什么需要另一種語言?
正如在 [上個月的專欄](/developerworks/cn/java/j-alj07064/)中介紹的,Groovy 不是與 JRE 兼容的惟一腳本語言。Python、Ruby 和 Smalltalk 就是成功地移植到 Java 平臺上的三種腳本語言。對于一些開發人員,這帶來了問題:為什么要另一種語言?畢竟,我們許多人已經將 Java 代碼與 Jython 或者 JRuby 結合來快速開發應用程序,為什么還要學習另一種語言?回答是 _您不一定要學習一種新語言以用 Groovy 編碼_。Groovy 與其他 JRE 兼容腳本語言的不同在于它的語法以及重用 Java 庫。Jython 和 JRuby 共享它們前身(分別是 Python 和 Ruby)的外觀,Groovy 讓人覺得就像是 Java 語言,不過限制要少得多。
## 關于本系列
雖然本系列的大多數讀者熟悉 Java 語言以及它是如何在跨平臺虛擬機上運行的,但是只有少數人知道 Java Runtime Environment 可以承載 Java 語言之外的語言。本系列文章對 JRE 的多種替代語言進行了綜述。這里討論的大多數語言是開放源代碼的,許多是免費使用的,有少數是商業產品,必須購買。在 [_alt.lang.jre_](http://www.ibm.com/developerworks/views/java/articles.jsp?S_TACT=105AGX52&expand&sort_order=desc&search_by=alt.lang.jre&S_CMP=cn-a-j&show_abstract=true&sort_by=Date&view_by=Search)系列中介紹的所有語言都得到了 JRE 支持,并且作者相信它們增強了 Java 平臺的動態性和靈活性特征。
像 Jython 這樣的語言是在它們的父語言庫上建立的,而 Groovy 使用了 Java 開發人員最熟悉的功能和庫 _—— 但是將它們放到了一個敏捷開發框架中_。敏捷開發的基本宗旨是代碼應該很好地適合范圍廣泛的任務,并可以不同的方式應用。Groovy 通過以下方式落實了這些宗旨:
* 使開發人員不用編譯。
* 允許動態類型。
* 使合成結構容易。
* 使其腳本可以在普通 Java 應用程序中使用。
* 提供一個 shell 解析器。
這些特性使 Groovy 成為一種特別容易學習和使用的語言,不管您是有經驗的 Java 開發人員還是剛接觸 Java 平臺。在下面幾節中,我將詳細討論上述特性。
* * *
## 看呀,沒有 javac!
像許多腳本語言一樣,Groovy 不用為運行時編譯。這意味著 Groovy 腳本是 _在它們運行時_解釋的,就像 JavaScript 是在觀看 Web 頁時由瀏覽器解釋的一樣。運行時判斷會有執行速度的代價,這有可能使腳本語言不能用于對性能有要求的項目,但是無編譯的代碼在構建-運行周期中可以提供很多好處。運行時編譯使 Groovy 成為快速原型設計、構建不同的實用程序和測試框架的理想平臺。
## 腳本的能力
腳本語言很流行,因為它們容易學習并且為開發人員設置的限制較少。腳本語言通常使用簡單的、相當簡潔的語法,這使開發人員可以用比大多數編程語言所需要的更少的代碼創建真實世界的應用程序。像 Perl、Python、Ruby 和現在的 Groovy,用其敏捷方式編寫代碼而使編程工作達到一個新的效率水平。這種提高的敏捷性通常會使開發人員的效率提高。腳本語言的成功表明腳本不是一種小范圍內使用的技術或者黑客的娛樂工具,而是一種由像 Google、Yahoo 和 IBM 這樣的世界級公司所使用的切實可行的技術。
例如,運行腳本 Emailer.groovyin Groovy 就是在命令行鍵入 `groovy Emailer.groovy` 這么容易。如果希望運行同樣的 Java 文件(Emailer.java),顯然必須鍵入額外的命令: `javac Emailer.java` ,然后是 `java Emailer` 。雖然這看起來可能有些微不足道,但是可以容易設想運行時編譯在應用程序開發的更大上下文中的好處。
可以在稍后看到,Groovy 還允許腳本放棄 main 方法以靜態地運行一個關聯的應用程序。
* * *
## 動態 dynamo
像其他主流腳本語言一樣,Groovy 不需要像 C++ 和 Java 語言這樣的正式語言的顯式類型。在 Groovy 中,一個對象的類型是在運行時動態發現的,這極大地減少了要編寫的代碼數量。首先可以通過分析清單 1 和 2 中的簡單例子看到這一點。
清單 1 顯示了在 Java 語言中如何將一個本地變量聲明為 `String` 。注意必須聲明類型、名和值。
##### 清單 1\. Java 靜態類型
```
String myStr = "Hello World";
```
在清單 2 中,您看到同樣的聲明,但是不需要聲明變量類型。
##### 清單 2\. Groovy 動態類型
```
myStr = "Hello World"
```
您可能還注意到了,在清單 2 中我可以去掉聲明中的分號。在定義方法及其相關的參數時動態類型有戲劇性的后果:多態具有了全新的意義!事實上,使用動態類型, _不使用_繼承就可以得到多態的全部能力。在清單 3 中,可以真正開始看到動態類型在 Groovy 的靈活性方面所起的作用。
##### 清單 3\. 更多 Groovy 動態類型
```
class Song{
length
name
}
class Book{
name
author
}
def doSomething(thing){
println "going to do something with a thing named = " + thing.name
}
```
這里,我定義了兩個 Groovy 類, `Song` 和 `Book` ,我將在后面對它們進一步討論。這兩個類都包含一個 `name` 屬性。我還定義了一個函數 `doSomething` ,它以一個 `thing` 為參數,并試圖打印這個對象的 `name` 屬性。
因為 `doSomething` 函數沒有定義其輸入參數的類型,只要對象包含一個 `name` 屬性,那么它就可以工作。因此,在清單 4 中,可以看到在使用 `Song` 和 `Book` 的實例作為 `doSomething` 的輸入時會有什么現象。
##### 清單 4\. 試驗動態類型
```
mySong = new Song(length:90, name:"Burning Down the House")
myBook = new Book(name:"One Duck Stuck", author:"Phyllis Root")
doSomething(mySong) //prints Burning Down the House
doSomething(myBook) //prints One Duck Stuck
anotherSomething = doSomething
anotherSomething(myBook) //prints One Duck Stuck
```
除了展示 Groovy 中的動態類型,清單 4 的最后兩行還揭示了創建對一個函數的引用有多容易。這是因為在 Groovy 中 _所有東西_都是對象,包括函數。
關于 Groovy 的動態類型聲明最后要注意的是,它會導致更少的 `import` 語句。盡管 Groovy 需要 import 以顯式使用類型,但是這些 import 可以使用別名以提供更短的名字。
### 動態類型綜述
下面兩個例子將到目前為止討論過的 Groovy 中的動態類型的內容放到一起。下面的 Java 代碼組和 Groovy 代碼組利用了 Freemarker(參閱 [參考資料](#resources)),這是一個開放源代碼模板引擎。這兩組代碼都只是簡單地用一個目錄和文件名創建一個 `Template` 對象,然后將相應對象的內容打印到標準輸出,當然,不同之處是每一組代碼處理這項任務所需要的代碼量。
##### 清單 5\. 簡單的 TemplateReader Java 類
```
import java.io.File;
import java.io.IOException;
import freemarker.template.Configuration;
import freemarker.template.Template;
public class TemplateReader {
public static void main(String[] args) {
try{
Configuration cfg = Configuration.getDefaultConfiguration();
cfg.setDirectoryForTemplateLoading(
new File("C:\\dev\\projects\\http-tester\\src\\conf"));
Template temp = cfg.getTemplate("vendor-request.tmpl");
System.out.println(temp.toString());
}catch(IOException e){
e.printStackTrace();
}
}
}
```
初看之下,清單 5 中的 Java 代碼相當簡單 —— 特別是如果以前從來沒見過腳本代碼時。幸運的是,有清單 6 中的 Groovy 作為對比。現在這段代碼很簡單!
##### 清單 6\. 用 Groovy 編寫的更簡單的 TemplateReader
```
import freemarker.template.Configuration as tconf
import java.io.File
cfg = tconf.getDefaultConfiguration()
cfg.setDirectoryForTemplateLoading(
new File("C:\\dev\\projects\\http-tester\\src\\conf"))
temp = cfg.getTemplate("vendor-request.tmpl")
println temp.toString()
```
Groovy 代碼只有 Java 代碼的一半那么長,下面是原因:
* Groovy 代碼只需要一半的 `import` 語句。還要注意, `freemarker.template.Configuration` 使用了別名 `tconf` ,使得語法更短。
* Groovy 允許類型為 `Template` 的變量 `tmpl` 不聲明其類型。
* Groovy 不需要 `class` 聲明或者 `main` 方法。
* Groovy 不關心任何相應異常,使您可以不用導入 Java 代碼中需要的 `IOException` 。
現在,在繼續之前,想一下您所編寫的最后一個 Java 類。您可能不得不編寫很多 import 并聲明類型,并在后面加上同樣數量的分號。考慮用 Groovy 編寫同樣的代碼會是什么情況。可以使用簡練得多的語法,不需要遵守這么多的規則,并且得到完全相同的行為。
想一下,如果您正好是剛剛開始……
* * *
## 特別靈活的語法
談到語法,靈活性是更有效地開發代碼的主要因素。很像其有影響的對手(Python、Ruby 和 Smalltalk),Groovy 極大地簡化了核心庫的使用和它所模擬的語言(在這里是 Java 語言)的構造。為了讓您對 Groovy 語法的靈活性有一個大體概念,我將展示它的一些主要結構,即類、函數(通過 `def` 關鍵詞)、閉包、集合、范圍、映射和迭代器。
### 類
在字節碼水平,Groovy 類是真正的 Java 類。不同之處在于 Groovy 將類中定義的所有內容都默認為 `public` ,除非定義了特定的訪問修飾符。而且,動態類型應用到字段和方法,不需要 `return` 語句。
在清單 7 中可以看到 Groovy 中類定義的例子,其中類 `Dog` 有一個 `getFullName` 方法,它實際上返回一個表示 `Dog` 的全名的 `String` 。并且所有方法都隱式地為 `public` 。
##### 清單 7\. 示例 Groovy 類:Dog
```
class Dog{
name
bark(){
println "RUFF! RUFF!"
}
getFullName(master){
name + " " + master.lname
}
obeyMaster(){
println "I hear you and will not obey."
}
}
```
在清單 8 中,推廣到有兩個屬性 —— `fname` 和 `lname` —— 的類 `DogOwner` ,就是這么簡單!
##### 清單 8\. 示例 Groovy 類:DogOwner
```
class DogOwner{
fname
lname
trainPet(pet){
pet.obeyMaster()
}
}
```
在清單 9 中,用 Groovy 設置屬性并對 `Dog` 和 `DogOwner` 實例調用方法。現在很明顯,使用 Groovy 類比 Java 類要容易得多。雖然需要 `new` 關鍵詞,但是類型是可選的,且設置屬性(它隱式為 public)是相當輕松的。
##### 清單 9\. 使用 Groovy 類
```
myDog = new Dog()
myDog.name = "Mollie"
myDog.bark()
myDog.obeyMaster()
me = new DogOwner()
me.fname = "Ralf"
me.lname = "Waldo"
me.trainPet(myDog)
str = myDog.getFullName(me)
println str // prints Mollie Waldo
```
注意在 `Dog` 類中定義的 `getFullName` 方法返回一個 `String` 對象,在這里它是 “ `Mollie Waldo` ”。
## 第一類對象
_第一類對象_ 是可以在運行時用數據創建并使用的對象。第一類對象還可以傳遞給函數和由函數輸出、作為變量存儲、由其他對象返回。Java 語言自帶的基本數據類型,如 `int` 和 `boolean` ,不認為是第一類對象。許多面向對象純粹論者哀嘆這個小細節,一些人據此提出 Java 語言是否是真正的面向對象語言。Groovy 通過將所有內容聲明為對象而解決了這一問題。
### Def
除了像許多腳本語言那樣將所有對象指定為第一類對象(見側欄),Groovy 還讓您創建 _第一類函數_,它本身實質上就是對象。它們是用 `def` 關鍵詞定義的并在類定義之外。您實際上在 [清單 3](#code3) 中已經看到了如何用 `def` 關鍵詞定義第一類函數,并在 [清單 4](#code4)中看到使用了一個函數。Groovy 的第一類函數定義簡單腳本時特別有用。
### 閉包
Groovy 中最令人興奮和最強大的功能是支持閉包。 _閉包(Closure)_是第一類對象,它類似于 Java 語言中的匿名內部類。閉包和匿名內部類都是可執行的一段代碼,不過這兩者之間有一些細微的不同。狀態是自動傳入傳出閉包的。閉包可以有名字。它們可以重復使用。而且,最重要且對 Groovy 同樣成立的是,閉包遠比匿名內部類要靈活得多!
清單 10 展示了閉包的強大。清單中新的和改進的 `Dog` 類包括一個 `train` 方法,它實際上執行創建了 `Dog` 實例的閉包。
##### 清單 10\. 使用閉包
```
class Dog{
action
train(){
action.call()
}
}
sit = { println "Sit, Sit! Sit! Good dog"}
down = { println "Down! DOWN!" }
myDog = new Dog(action:sit)
myDog.train() // prints Sit, Sit! Sit! Good dog
mollie = new Dog(action:down)
mollie.train() // prints Down! DOWN!
```
而且,閉包還可以接收參數。如清單 11 所示, `postRequest` 閉包接收兩個參數( `location` 和 `xml` ),并使用 Jakarta Commons HttpClient 庫(參閱 [參考資料](#resources))將一個 XML 文檔發送給指定位置。然后這個閉包返回一個表示響應的 `String` 。閉包定義下面是一個使用閉包的例子。事實上,調用閉包就像調用函數一樣。
##### 清單 11\. 使用帶參數的閉包
```
import org.apache.commons.httpclient.HttpClient
import org.apache.commons.httpclient.methods.PostMethod
postRequest = { location, xml |
clint = new HttpClient()
mthd = new PostMethod(location)
mthd.setRequestBody(xml)
mthd.setRequestContentLength(xml.length())
mthd.setRequestHeader("Content-type",
"text/xml; charset=ISO-8859-1")
statusCode = clint.executeMethod(mthd)
responseBody = mthd.getResponseBody()
mthd.releaseConnection()
return new String(responseBody)
}
loc = "http://localhost:8080/simulator/AcceptServlet/"
vxml = "<test><data>blah blah blah</data></test>"
str = postRequest(loc, vxml)
println str
```
## 自動裝箱
自動裝箱或者裝箱轉換是一個自動將像 `int` 、 `double` 和 `boolean` 這樣的基本數據類型自動轉換為可以在 `java.lang` 包中找到的它們的相應包裝類型的過程。這一功能出現在 J2SE 1.5 中,使開發人員不必在源代碼中手工編寫轉換代碼。
### 集合
將對象組織到像列表和映射這樣的數據結構中是一項基本的編碼任務,是我們大多數人每天要做的工作。像大多數語言一樣,Groovy 定義了一個豐富的庫以管理這些類型的集合。如果曾經涉足 Python 或者 Ruby,那么應該熟悉 Groovy 的集合語法。如清單 12 所示,創建一個列表與在 Java 語言中創建一個數組很類似。(注意,列表的第二項自動裝箱為一個 `Integer` 類型。)
##### 清單 12\. 使用集合
```
collect = ['groovy', 29, 'here', 'groovy']
```
除了使列表更容易處理,Groovy 還為集合增加了幾個新方法。這些方法使得,如 `統計` 值出現的次數、將整個列表 `結合` 到一起、對列表 `排序` 變得非常容易。可以在清單 13 中看到這些集合方法的使用。
##### 清單 13\. 使用 Groovy 集合
```
aCollect = [5, 9, 2, 2, 4, 5, 6]
println aCollect.join(' - ') // prints 5 - 9 - 2 - 2 - 4 - 5 - 6
println aCollect.count(2) // prints 2
println aCollect.sort() // prints [2, 2, 4, 5, 5, 6, 9]
```
**Maps**
像列表一樣,映射也是一種在 Groovy 中非常容易處理的數據結構。清單 14 中的映射包含兩個對象,鍵是 `name` 和 `date` 。注意可以用不同的方式取得值。
##### 清單 14\. 處理映射
```
myMap = ["name" : "Groovy", "date" : new Date()]
println myMap["date"]
println myMap.date
```
**范圍**
在處理集合時,很可能會大量使用 `范圍(Range)` 。 `范圍` 實際上是一個很直觀的概念,并且容易理解,利用它可以包含地或者排除地創建一組有序值。使用兩個點 ( `..` ) 聲明一個包含范圍,用三個點 ( `...` ) 聲明一個排除范圍,如清單 15 所示。
##### 清單 15\. 處理范圍
```
myRange = 29...32
myInclusiveRange = 2..5
println myRange.size() // prints 3
println myRange[0] // prints 29
println myRange.contains(32) //prints false
println myInclusiveRange.contains(5) //prints true
```
**用范圍實現循環**
在循環結構中,范圍可以實現相當巧妙的想法。在清單 16 中,將 `aRange` 定義為一個排除范圍,循環打印 a、b、c 和 d。
##### 清單 16\. 用范圍實現循環
```
aRange = 'a'...'e'
for (i in aRange){
println i
}
```
**集合的其他功能**
如果不熟悉 Python 和其他腳本語言,那么您在 Groovy 集合中發現的一些其他功能會讓您印象深刻。例如,創建了集合后,可以用負數在列表中反向計數,如清單 17 所示。
##### 清單 17\. 負索引
```
aList = ['python', 'ruby', 'groovy']
println aList[-1] // prints groovy
println aList[-3] // prints python
```
Groovy 還讓您可以用范圍分割列表。分割可獲得列表的準確子集,如清單 18 所示。
##### 清單 18\. 用范圍分割
```
fullName = "Andrew James Glover"
mName = fullName[7...13]
print "middle name: " + mName // prints James
```
**集合類似于 Ruby**
如果愿意的話,還可以將 Groovy 集合作為 Ruby 集合。可以用類似 Ruby 的語法,以 `<<` 語法附加元素、用 `+` 串接和用 `-` 對集合取差,甚至還可以用 `*` 語法處理集合的重復,如清單 19 所示。 注意,還可以用 `==` 比較集合。
##### 清單 19\. Ruby 風格的集合
```
collec = [1, 2, 3, 4, 5]
collec << 6 //appended 6 to collec
acol = ['a','b','c'] * 3 //acol now has 9 elements
coll = [10, 11]
coll2 = [12, 13]
coll3 = coll + coll2 //10,11,12,13
difCol = [1,2,3] - [1,2] //difCol is 3
assert [1, 2, 3] == [1, 2, 3] //true
```
### 迭代器
在 Groovy 中,迭代任何序列都相當容易。迭代字符序列所需要的就是一個簡單的 `for` 循環,如清單 20 所示。(正如您現在可能注意到的,Groovy 提供了比 Java 1.5 以前的傳統語法更自然的 `for` 循環語法。)
##### 清單 20\. 迭代器示例
```
str = "uncle man, uncle man"
for (ch in str){
println ch
}
```
Groovy 中的大多數對象具有像 `each` 和 `find` 這樣的以閉包為參數的方法。用閉包來迭代對象會產生幾種令人興奮的可能性,如清單 21 所示。
##### 清單 21\. 帶有迭代器的閉包
```
[1, 2, 3].each {
val = it
val += val
println val
}
[2, 4, 6, 8, 3].find { x |
if (x == 3){
println x
}
}
```
在清單 21 中,方法 `each` 作為迭代器。在這里,閉包添加元素的值,完成時 `val` 的值為 6。 `find` 方法也是相當簡單的。每一次迭代傳遞進元素。在這里,只是測試值是否為 3。
* * *
## Groovy 的高級內容
到目前為止,我著重講述的都是使用 Groovy 的基本方面,但是這種語言有比基本內容多得多的內容!我將以分析 Groovy 提供的一些高級開發功能作為結束,包括 Groovy 樣式的 JavaBeans 組件、文件 IO、正則表達式和用 `groovyc` 編譯。
### GroovyBean!
永遠不變的是,應用程序最后要使用類似 struct 的對象表示真實世界的實體。在 Java 平臺上,稱這些對象為 JavaBean 組件,它們通常用于表示訂單、客戶、資源等的業務對象。Groovy 由于其方便的簡寫語法,以及在定義了所需 bean 的屬性后自動提供構造函數,而簡化了 JavaBean 組件的編寫。結果自然就是極大地減少了代碼,正如您可以自己從清單 22 和 23 中看到的。
在清單 22 中,可看到一個簡單的 JavaBean 組件,它是用 Java 語言定義的。
##### 清單 22\. 一個簡單的 JavaBean 組件
```
public class LavaLamp {
private Long model;
private String baseColor;
private String liquidColor;
private String lavaColor;
public String getBaseColor() {
return baseColor;
}
public void setBaseColor(String baseColor) {
this.baseColor = baseColor;
}
public String getLavaColor() {
return lavaColor;
}
public void setLavaColor(String lavaColor) {
this.lavaColor = lavaColor;
}
public String getLiquidColor() {
return liquidColor;
}
public void setLiquidColor(String liquidColor) {
this.liquidColor = liquidColor;
}
public Long getModel() {
return model;
}
public void setModel(Long model) {
this.model = model;
}
}
```
在清單 23 中,可以看到用 Groovy 寫這個 bean 時所發生的事。所要做的就是定義屬性,Groovy 會自動給您一個很好的構造函數以供使用。Groovy 還使您在操縱 `LavaLamp` 的實例時有相當大的靈活性。例如,我們可以使用 Groovy 的簡寫語法 _或者_傳統的冗長的 Java 語言語法操縱 bean 的屬性。
##### 清單 23\. 用 Groovy 編寫的 JavaBeans 組件
```
class LavaLamp{
model
baseColor
liquidColor
lavaColor
}
llamp = new LavaLamp(model:1341, baseColor:"Black",
liquidColor:"Clear", lavaColor:"Green")
println llamp.baseColor
println "Lava Lamp model ${llamp.model}"
myLamp = new LavaLamp()
myLamp.baseColor = "Silver"
myLamp.setLavaColor("Red")
println "My Lamp has a ${myLamp.baseColor} base"
println "My Lava is " + myLamp.getLavaColor()
```
### 輕松的 IO
Groovy IO 操作很輕松,特別是與迭代器和閉包結合時。Groovy 使用標準 Java 對象如 `File` 、 `Reader` 和 `Writer` ,并用接收閉包作參數的額外方法增強了它們。如在清單 24 中,可以看到傳統的 `java.io.File` ,但是帶有額外的、方便的 `eachLine` 方法。
##### 清單 24\. Groovy IO
```
import java.io.File
new File("File-IO-Example.txt").eachLine{ line |
println "read the following line -> " + line
}
```
因為文件實質上是一系列行、字符等,所以可以相當簡單地迭代它們。 `eachLine` 方法接收一個閉包并迭代文件的每一行,在這里是 `File-IO-Example.txt` 。 以這種方式使用閉包是相當強大的,因為 Groovy 保證所有文件資源都是關閉的,不考慮任何異常。這意味著無需大量 `try` / `catch` / `finally` 子句就可以進行文件 IO!
### 高級編譯
Groovy 腳本實際上是字節碼級別的 Java 類。因此,可以容易地用 `groovyc` 編譯 Groovy 腳本。可以通過命令行或者 `Ant` 使用 `groovyc` 以生成腳本的類文件。這些類可以用普通 `java` 命令運行,只要 classpath 包括 `groovy.jar` 和 `asm.jar` ,這是 ObjectWeb 的字節碼操縱框架。要了解更多編譯 Groovy 的內容,請參閱 [參考資料](#resources)。
### 最大 RegEx
如果一種語言沒有正則表達式處理,則它是沒價值的。Groovy 使用 Java 平臺的 `java.util.regex` 庫 —— 但是做了少量基本的改變。例如,Groovy 使您可以用 `~` 表達式創建 `Pattern` 對象,用 `=~` 表達式創建 `Matcher` 對象,如清單 25 所示。
##### 清單 25\. Groovy RegEx
```
str = "Water, water, every where,
And all the boards did shrink;
Water, water, every where,
Nor any drop to drink."
if (str =~ 'water'){
println 'found a match'
}
ptrn = ~"every where"
nStr = (str =~ 'every where').replaceAll('nowhere')
println nStr
```
您可能已經注意到了,可以在上述清單中定義 `String` 、 `str` ,而無需為每一新行添加結束引號和 `+` 。這是因為 Groovy 放松了要求字符串串接的普通 Java 約束。運行這段 Groovy 腳本會對匹配 `water` 的情況打印出 `true` ,然后打印出一節詩,其中所有出現 “ `every where` ”的地方都替換為 “ `nowhere` ”。
## 關于 (band)shell
Groovy 提供了兩種不同的解釋器,使所有有效的 Groovy 表達式可以交互地執行。這些 shell 是特別強大的機制,可以用它們迅速學習 Groovy。
* * *
## 結束語
像所有嬰兒期的項目一樣,Groovy 是正在發展的語言。習慣于使用 Ruby 和 Python (或者 Jython)的開發人員可能會懷念 mixins、腳本導入(盡管可以將所需要的可導入腳本編譯為相應的 Java 類)和方法調用的命名參數等這些功能的方便性。 但是 Groovy 絕對是一種發展中的語言。隨著其開發人員數量的增加,它很有可能結合這些功能及更多功能。
同時,Groovy 有很多優點。它很好地融合了 Ruby、Python 和 Smalltalk 的一些最有用的功能,同時保留了基于 Java 語言的核心語法。對于熟悉 Java 平臺的開發人員,Groovy 提供了更簡單的替代語言,且幾乎不需要學習時間。對于剛接觸 Java 平臺的開發人員,它可以作為有更復雜語法和要求的 Java 語言的一個容易的入口點。
像在本系統討論的其他語言一樣,Groovy 不是要替代 Java 語言,而是作為它的另一種選擇。與這里討論的其他語言不一樣,Groovy 遵循 Java 規范,這意味著它有可能與 Java 平臺上的 Java 語言具有同等重要的作用。
在本月這一期 _alt.lang.jre_文章中,介紹了 Groovy 的基本框架和語法,以及它的一些高級編程功能。下個月將介紹在 Java 開發人員中最受歡迎的腳本語言: JRuby。
- 實戰 Groovy
- 實戰 Groovy: SwingBuilder 和 Twitter API,第 2 部分
- 實戰 Groovy: SwingBuilder 和 Twitter API,第 1 部分
- 實戰 Groovy: @Delegate 注釋
- 實戰 Groovy: 使用閉包、ExpandoMetaClass 和類別進行元編程
- 實戰 Groovy: 構建和解析 XML
- 實戰 Groovy: for each 剖析
- 實戰 Groovy: Groovy:Java 程序員的 DSL
- 實戰 Groovy: 關于 MOP 和迷你語言
- 實戰 Groovy: 用 curry 過的閉包進行函數式編程
- 實戰 Groovy: Groovy 的騰飛
- 實戰 Groovy: 在 Java 應用程序中加一些 Groovy 進來
- 實戰 Groovy: 用 Groovy 生成器作標記
- 實戰 Groovy: 用 Groovy 打造服務器端
- 實戰 Groovy: 使用 Groovy 模板進行 MVC 編程
- 實戰 Groovy: 用 Groovy 進行 JDBC 編程
- 實戰 Groovy: 用 Groovy 進行 Ant 腳本編程
- 實戰 Groovy: 用 Groovy 更迅速地對 Java 代碼進行單元測試
- alt.lang.jre: 感受 Groovy