級別: 初級 |
CTO, Vanward Technologies
2004 年 8 月
雖然 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 (請參閱 參考資料)的開放評論中,Groovy 的共同規范領導者 Richard Monson-Haefel 說他對 Groovy 的支持是建立在總有一天 Java 平臺要包括一種敏捷開發語言這一信念上。與許多移植到 Java 平臺的腳本語言不同,Groovy 是 為 JRE 而寫的。在規范請求中(參閱 參考資料),Groovy 的制造者提出了“Java 不僅是一種編程語言,更是一個健壯的平臺,可以有多種語言在上面運行和共存”(Monson-Haefel 語)的思想。
新 alt.lang.jre 專欄的這第二期文章的目的是讓讀者了解 Groovy。我首先回答關于這種新語言的一些最顯然的問題(為什么需要它?),然后以代碼為基礎概述 Groovy 最令人興奮的功能。
為什么需要另一種語言?
正如在 上個月的專欄 中介紹的,Groovy 不是與 JRE 兼容的惟一腳本語言。Python、Ruby 和 Smalltalk 就是成功地移植到 Java 平臺上的三種腳本語言。對于一些開發人員,這帶來了問題:為什么要另一種語言?畢竟,我們許多人已經將 Java 代碼與 Jython 或者 JRuby 結合來快速開發應用程序,為什么還要學習另一種語言?回答是 您不一定要學習一種新語言以用 Groovy 編碼。Groovy 與其他 JRE 兼容腳本語言的不同在于它的語法以及重用 Java 庫。Jython 和 JRuby 共享它們前身(分別是 Python 和 Ruby)的外觀,Groovy 讓人覺得就像是 Java 語言,不過限制要少得多。
關于本系列 |
像 Jython 這樣的語言是在它們的父語言庫上建立的,而 Groovy 使用了 Java 開發人員最熟悉的功能和庫 —— 但是將它們放到了一個敏捷開發框架中。敏捷開發的基本宗旨是代碼應該很好地適合范圍廣泛的任務,并可以不同的方式應用。Groovy 通過以下方式落實了這些宗旨:
- 使開發人員不用編譯。
- 允許動態類型。
- 使合成結構容易。
- 使其腳本可以在普通 Java 應用程序中使用。
- 提供一個 shell 解析器。
這些特性使 Groovy 成為一種特別容易學習和使用的語言,不管您是有經驗的 Java 開發人員還是剛接觸 Java 平臺。在下面幾節中,我將詳細討論上述特性。
看呀,沒有 javac!
像許多腳本語言一樣,Groovy 不用為運行時編譯。這意味著 Groovy 腳本是 在它們運行時 解釋的,就像 JavaScript 是在觀看 Web 頁時由瀏覽器解釋的一樣。運行時判斷會有執行速度的代價,這有可能使腳本語言不能用于對性能有要求的項目,但是無編譯的代碼在構建-運行周期中可以提供很多好處。運行時編譯使 Groovy 成為快速原型設計、構建不同的實用程序和測試框架的理想平臺。
腳本的能力 |
例如,運行腳本 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
。注意必須聲明類型、名和值。
|
在清單 2 中,您看到同樣的聲明,但是不需要聲明變量類型。
清單 2. Groovy 動態類型
|
您可能還注意到了,在清單 2 中我可以去掉聲明中的分號。在定義方法及其相關的參數時動態類型有戲劇性的后果:多態具有了全新的意義!事實上,使用動態類型,不使用 繼承就可以得到多態的全部能力。在清單 3 中,可以真正開始看到動態類型在 Groovy 的靈活性方面所起的作用。
清單 3. 更多 Groovy 動態類型
|
這里,我定義了兩個 Groovy 類,Song
和 Book
,我將在后面對它們進一步討論。這兩個類都包含一個 name
屬性。我還定義了一個函數 doSomething
,它以一個 thing
為參數,并試圖打印這個對象的 name
屬性。
因為 doSomething
函數沒有定義其輸入參數的類型,只要對象包含一個 name
屬性,那么它就可以工作。因此,在清單 4 中,可以看到在使用 Song
和 Book
的實例作為 doSomething
的輸入時會有什么現象。
|
除了展示 Groovy 中的動態類型,清單 4 的最后兩行還揭示了創建對一個函數的引用有多容易。這是因為在 Groovy 中 所有東西 都是對象,包括函數。
關于 Groovy 的動態類型聲明最后要注意的是,它會導致更少的 import
語句。盡管 Groovy 需要 import 以顯式使用類型,但是這些 import 可以使用別名以提供更短的名字。
動態類型綜述
下面兩個例子將到目前為止討論過的 Groovy 中的動態類型的內容放到一起。下面的 Java 代碼組和 Groovy 代碼組利用了 Freemarker(參閱 參考資料),這是一個開放源代碼模板引擎。這兩組代碼都只是簡單地用一個目錄和文件名創建一個 Template
對象,然后將相應對象的內容打印到標準輸出,當然,不同之處是每一組代碼處理這項任務所需要的代碼量。
|
初看之下,清單 5 中的 Java 代碼相當簡單 —— 特別是如果以前從來沒見過腳本代碼時。幸運的是,有清單 6 中的 Groovy 作為對比。現在這段代碼很簡單!
清單 6. 用 Groovy 編寫的更簡單的 TemplateReader
|
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
。
|
在清單 8 中,推廣到有兩個屬性 —— fname
和 lname
—— 的類 DogOwner
,就是這么簡單!
|
在清單 9 中,用 Groovy 設置屬性并對 Dog
和 DogOwner
實例調用方法。現在很明顯,使用 Groovy 類比 Java 類要容易得多。雖然需要 new
關鍵詞,但是類型是可選的,且設置屬性(它隱式為 public)是相當輕松的。
|
注意在 Dog
類中定義的 getFullName
方法返回一個 String
對象,在這里它是 “Mollie Waldo
”。
第一類對象 |
Def
除了像許多腳本語言那樣將所有對象指定為第一類對象(見側欄),Groovy 還讓您創建 第一類函數,它本身實質上就是對象。它們是用 def
關鍵詞定義的并在類定義之外。您實際上在 清單 3 中已經看到了如何用 def
關鍵詞定義第一類函數,并在 清單 4 中看到使用了一個函數。Groovy 的第一類函數定義簡單腳本時特別有用。
閉包
Groovy 中最令人興奮和最強大的功能是支持閉包。閉包(Closure) 是第一類對象,它類似于 Java 語言中的匿名內部類。閉包和匿名內部類都是可執行的一段代碼,不過這兩者之間有一些細微的不同。狀態是自動傳入傳出閉包的。閉包可以有名字。它們可以重復使用。而且,最重要且對 Groovy 同樣成立的是,閉包遠比匿名內部類要靈活得多!
清單 10 展示了閉包的強大。清單中新的和改進的 Dog
類包括一個 train
方法,它實際上執行創建了 Dog
實例的閉包。
|
而且,閉包還可以接收參數。如清單 11 所示,postRequest
閉包接收兩個參數(location
和 xml
),并使用 Jakarta Commons HttpClient 庫(參閱 參考資料)將一個 XML 文檔發送給指定位置。然后這個閉包返回一個表示響應的 String
。閉包定義下面是一個使用閉包的例子。事實上,調用閉包就像調用函數一樣。
|
自動裝箱 |
集合
將對象組織到像列表和映射這樣的數據結構中是一項基本的編碼任務,是我們大多數人每天要做的工作。像大多數語言一樣,Groovy 定義了一個豐富的庫以管理這些類型的集合。如果曾經涉足 Python 或者 Ruby,那么應該熟悉 Groovy 的集合語法。如清單 12 所示,創建一個列表與在 Java 語言中創建一個數組很類似。(注意,列表的第二項自動裝箱為一個 Integer
類型。)
|
除了使列表更容易處理,Groovy 還為集合增加了幾個新方法。這些方法使得,如統計
值出現的次數、將整個列表結合
到一起、對列表排序
變得非常容易。可以在清單 13 中看到這些集合方法的使用。
|
Maps
像列表一樣,映射也是一種在 Groovy 中非常容易處理的數據結構。清單 14 中的映射包含兩個對象,鍵是 name
和 date
。注意可以用不同的方式取得值。
|
范圍
在處理集合時,很可能會大量使用 范圍(Range)
。 范圍
實際上是一個很直觀的概念,并且容易理解,利用它可以包含地或者排除地創建一組有序值。使用兩個點 (..
) 聲明一個包含范圍,用三個點 (...
) 聲明一個排除范圍,如清單 15 所示。
|
用范圍實現循環
在循環結構中,范圍可以實現相當巧妙的想法。在清單 16 中,將 aRange
定義為一個排除范圍,循環打印 a、b、c 和 d。
|
集合的其他功能
如果不熟悉 Python 和其他腳本語言,那么您在 Groovy 集合中發現的一些其他功能會讓您印象深刻。例如,創建了集合后,可以用負數在列表中反向計數,如清單 17 所示。
|
Groovy 還讓您可以用范圍分割列表。分割可獲得列表的準確子集,如清單 18 所示。
清單 18. 用范圍分割
|
集合類似于 Ruby
如果愿意的話,還可以將 Groovy 集合作為 Ruby 集合。可以用類似 Ruby 的語法,以 <<
語法附加元素、用 +
串接和用 -
對集合取差,甚至還可以用 *
語法處理集合的重復,如清單 19 所示。 注意,還可以用 ==
比較集合。
|
迭代器
在 Groovy 中,迭代任何序列都相當容易。迭代字符序列所需要的就是一個簡單的 for
循環,如清單 20 所示。(正如您現在可能注意到的,Groovy 提供了比 Java 1.5 以前的傳統語法更自然的 for
循環語法。)
|
Groovy 中的大多數對象具有像 each
和 find
這樣的以閉包為參數的方法。用閉包來迭代對象會產生幾種令人興奮的可能性,如清單 21 所示。
|
在清單 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 組件
|
在清單 23 中,可以看到用 Groovy 寫這個 bean 時所發生的事。所要做的就是定義屬性,Groovy 會自動給您一個很好的構造函數以供使用。Groovy 還使您在操縱 LavaLamp
的實例時有相當大的靈活性。例如,我們可以使用 Groovy 的簡寫語法或者 傳統的冗長的 Java 語言語法操縱 bean 的屬性。
|
輕松的 IO
Groovy IO 操作很輕松,特別是與迭代器和閉包結合時。Groovy 使用標準 Java 對象如 File
、Reader
和 Writer
,并用接收閉包作參數的額外方法增強了它們。如在清單 24 中,可以看到傳統的 java.io.File
,但是帶有額外的、方便的 eachLine
方法。
|
因為文件實質上是一系列行、字符等,所以可以相當簡單地迭代它們。eachLine
方法接收一個閉包并迭代文件的每一行,在這里是 File-IO-Example.txt
。 以這種方式使用閉包是相當強大的,因為 Groovy 保證所有文件資源都是關閉的,不考慮任何異常。這意味著無需大量 try
/catch
/finally
子句就可以進行文件 IO!
高級編譯
Groovy 腳本實際上是字節碼級別的 Java 類。因此,可以容易地用 groovyc
編譯 Groovy 腳本。可以通過命令行或者 Ant
使用 groovyc
以生成腳本的類文件。這些類可以用普通 java
命令運行,只要 classpath 包括 groovy.jar
和 asm.jar
,這是 ObjectWeb 的字節碼操縱框架。要了解更多編譯 Groovy 的內容,請參閱 參考資料。
最大 RegEx
如果一種語言沒有正則表達式處理,則它是沒價值的。Groovy 使用 Java 平臺的 java.util.regex
庫 —— 但是做了少量基本的改變。例如,Groovy 使您可以用 ~
表達式創建 Pattern
對象,用 =~
表達式創建 Matcher
對象,如清單 25 所示。
|
您可能已經注意到了,可以在上述清單中定義 String
、str
,而無需為每一新行添加結束引號和 +
。這是因為 Groovy 放松了要求字符串串接的普通 Java 約束。運行這段 Groovy 腳本會對匹配 water
的情況打印出 true
,然后打印出一節詩,其中所有出現 “every where
”的地方都替換為 “nowhere
”。
關于 (band)shell |
結束語
像所有嬰兒期的項目一樣,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。
- 新 alt.lang.jre 系列是上個月開始的,首先是 Barry Feigenbaum 的文章 “Get to know Jython”(developerWorks,2004 年 7 月)。
- 從 Groovy 開放源代碼項目頁 下載 Groovy,在這里還可以學習更多有關編譯、單元測試、正則表達式等之類的內容。
- 可以在 Java Community Process 主頁 找到“JSR 241: The Groovy programming language”。
- 閱讀 James Strachan 的“Groovy -- the birth of a new dynamic language for the Java platform”(Radio Userland,James Strachan 的 Weblog,2003 年 8 月),對 Groovy 背后的思路有一個概念。
- 在 java.net weblogs 頁 上閱讀更多 Richard Monson-Haefel 對 Groovy 的思想。
- Groovy 的一個最強大的功能是它的敏捷性。通過 Roy Miller 的“揭開極端編程的神秘面紗:重訪“XP 精華”,第 1 部分”(developerWorks,2002 年 8 月)學習有關敏捷開發(或者 XP) 的更多底層原理。
- Richard Hightower 和 Nicholas Lesiecki 的 Java tools for extreme programming(摘自 developerWorks,2002 年 7 月)是在 Java 平臺上進行敏捷開發的從業者指導,包括關于“Building Java applications with Ant”的一章。
- 通過 Malcolm Davis 的 “利用 Ant 和 JUnit 進行增量開發” (developerWorks,2000 年 11 月),學習有關用 Ant 構建 Java(因而也包括 Groovy) 應用程序的內容。
- 在 “讓編譯和測試過程自動化” (developerWorks,2001 年 8 月)中,Erik Hatcher 為您展示了如何結合 Ant 和 JUnit 以朝 XP 天堂更進一步。
- Maven 是 Ant 的替代物,它可以很好地完成項目管理任務。通過 Charles Chan 的“項目管理:Maven 讓事情變得簡單” (developerWorks,2003 年 4 月),學習有關 Maven 的更多內容。
- 面向方面的程序設計是一種構建高度去耦和可擴展的企業系統的敏捷開發技術。通過 Andrew Glover 的 “AOP 解決緊密耦合的難題” (developerWorks,2004 年 2 月),學習有關 AOP 的更多內容。
- JustGroovy 是一個專門針對 Groovy 的 Web 網站。
- 在清單 6 中,開放源代碼模板引擎 Freemarker 結合了 Java 代碼和 Groovy 代碼段。
- 清單 11 中使用了 Jakarta Commons HttpClient 庫。
- Groovy 如果沒有像 Python 和 Ruby 這樣的語言的強大影響是不會變成今天這樣的。
- 可以在 developerWorks Java 技術專區 找到關于 Java 編程各個方面的文章。.
- 訪問 Developer Bookstore,獲取技術書籍的完整列表,其中包括數百本 Java 相關主題 的書籍。
- 還請參閱 Java 技術專區教程頁 以獲得 developerWorks 上關于 Java 的免費教程的完整清單。
- 是否對無需通常的高成本入口點(entry point )或短期評估許可證的 IBM 測試產品感興趣?developerWorks Subscription 針對 WebSphere?、DB2?、Lotus?、Rational? 和 Tivoli? 產品提供了低成本的 12 個月單用戶許可證,包括基于 Eclipse 的 WebSphere Studio IDE,用于開發、測試、評估和展示您的應用程序。
關于作者 Andrew Glover 是 Vanward Technologies 的 CTO,這是華盛頓特區中心的一家專門從事構建自動測試框架的公司,這種框架可以降低軟件 bug 數量、減少集成和測試次數,并改進代碼整體穩定性。 |