免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
精通 Groovy

在 IBM Bluemix 云平臺上開發(fā)并部署您的下一個(gè)應(yīng)用。

現(xiàn)在就開始免費(fèi)試用

開始之前

了解本教程的主要內(nèi)容,以及如何從中獲得最大收獲。

關(guān)于本教程

如果現(xiàn)在有人要開始完全重寫 Java,那么 Groovy 就像是 Java 2.0。Groovy 并沒有取代 Java,而是作為 Java 的補(bǔ)充,它提供了更簡單、更靈活的語法,可以在運(yùn)行時(shí)動態(tài)地進(jìn)行類型檢查。您可以使用 Groovy 隨意編寫 Java 應(yīng)用程序,連接 Java 模塊,甚至擴(kuò)展現(xiàn)有的 Java 應(yīng)用程序 — 甚至可以用 Groovy 對 Java 代碼進(jìn)行單元測試。Groovy 的美妙之處還在于,它能夠比編寫純粹的 Java 代碼更快地完成所有工作 — 有時(shí)候會快許多。

在本教程中,您將了解到 Groovy 是一門動態(tài)語言,它能夠像 Java 語言本身一樣很好地應(yīng)用于 Java 平臺。

學(xué)習(xí)目標(biāo)

本教程將逐步向您介紹 Groovy 的基本概念。您將學(xué)習(xí) Groovy 集合、Groovy 類,當(dāng)然還有 Groovy 的語法。完成本教程之后,您將了解將 Java 和 Groovy 結(jié)合使用的好處,從此您將能夠在日常的 Java 開發(fā)中使用 Groovy。

前提條件

為了從本教程得到最大收獲,您應(yīng)該熟悉 Java 語法和在 Java 平臺上進(jìn)行面向?qū)ο箝_發(fā)的基本概念。

系統(tǒng)需求

要嘗試本教程的代碼,需要安裝以下環(huán)境之一:

另外,本章教程假設(shè)您正在使用 Eclipse IDE。不需要安裝 Groovy,因?yàn)楸窘坛虝榻B如何安裝 Groovy Eclipse 插件。

本教程推薦系統(tǒng)的配置如下:

  • 支持 Sun JDK 1.5.0_09(或更高版本)或 IBM JDK 1.5.0 SR3 的系統(tǒng),擁有至少 500 MB 主內(nèi)存
  • 至少 20 MB 可用硬盤空間,用來安裝本教程涉及的軟件組件和示例

本教程的操作說明和示例均基于 Microsoft Windows 操作系統(tǒng)。本教程涉及的所有工具在 Linux 和 Unix 系統(tǒng)上也能工作。

回頁首

關(guān)于 Groovy

這一節(jié)將學(xué)習(xí) Groovy 的基礎(chǔ)知識:它是什么,它與 Java 語言和 JVM 的關(guān)系,以及編寫 Groovy 代碼的一些要點(diǎn)。

什么是 Groovy?

Groovy 是 JVM 的一個(gè)替代語言 —替代 是指可以用 Groovy 在 Java 平臺上進(jìn)行 Java 編程,使用方式基本與使用 Java 代碼的方式相同。在編寫新應(yīng)用程序時(shí),Groovy 代碼能夠與 Java 代碼很好地結(jié)合,也能用于擴(kuò)展現(xiàn)有代碼。目前的 Groovy 版本是 1.5.4,在 Java 1.4 和 Java 5 平臺上都能使用,也能在 Java 6 上使用。

Groovy 的一個(gè)好處是,它的語法與 Java 語言的語法很相似。雖然 Groovy 的語法源于 Smalltalk 和 Ruby 這類語言的理念,但是可以將它想像成 Java 語言的一種更加簡單、表達(dá)能力更強(qiáng)的變體。(在這點(diǎn)上,Ruby 與 Groovy 不同,因?yàn)樗恼Z法與 Java 語法差異很大。)

許多 Java 開發(fā)人員非常喜歡 Groovy 代碼和 Java 代碼的相似性。從學(xué)習(xí)的角度看,如果知道如何編寫 Java 代碼,那就已經(jīng)了解 Groovy 了。Groovy 和 Java 語言的主要區(qū)別是:完成同樣的任務(wù)所需的 Groovy 代碼比 Java 代碼更少。(有時(shí)候會少很多?。?/p>

Groovy 快捷方式

開始使用 Groovy 時(shí),您會發(fā)現(xiàn)它使日常的編程活動變得快了許多。完成本教程之后,您會了解更多的 Groovy 語法快捷方式。不過現(xiàn)在只需知道以下這些要點(diǎn):

  • Groovy 的松散的 Java 語法允許省略分號和修改符。
  • 除非另行指定,Groovy 的所有內(nèi)容都為 public
  • Groovy 允許定義簡單腳本,同時(shí)無需定義正規(guī)的 class 對象。
  • Groovy 在普通的常用 Java 對象上增加了一些獨(dú)特的方法和快捷方式,使得它們更容易使用。
  • Groovy 語法還允許省略變量類型。

Groovy 的新增特性

雖然 Groovy 允許省略 Java 語法中的一些元素,但也增加了一些新特性,例如本地集合、內(nèi)置的正則表達(dá)式和閉包。在標(biāo)準(zhǔn)的 Java 代碼中,如果想要?jiǎng)?chuàng)建一個(gè)項(xiàng)列表,首先要導(dǎo)入 java.util.ArrayList,然后程序化地初始化 ArrayList 實(shí)例,然后 再向?qū)嵗刑砑禹?xiàng)。在 Groovy 中,列表和映射都內(nèi)置在語法中 — 無需導(dǎo)入任何內(nèi)容。正則表達(dá)式也不需要額外的導(dǎo)入或?qū)ο?;它們可以通過特殊的 Groovy 語法來創(chuàng)建。

關(guān)于閉包

對于任何 Java 開發(fā)人員來說,閉包都是一個(gè)令人興奮的新技巧。這些神奇的構(gòu)造將會包含在未來的 Java 發(fā)行版(很可能是 Java 7)中,成為正式的 Java 語法,但現(xiàn)在已經(jīng)可以在 Groovy 中使用了??梢詫?em>閉包 想像為一個(gè)代碼塊,可以現(xiàn)在定義,以后再執(zhí)行??梢允褂眠@些強(qiáng)大的構(gòu)造做許多漂亮的事,不過最著名的是簡化迭代。使用 Groovy 之后,就有可能再也不需要編寫 Iterator 實(shí)例了。

動態(tài)的 Groovy

從技術(shù)上講,Groovy 可能是您最近聽說過的類型最松散的動態(tài)語言之一。從這個(gè)角度講,Groovy 與 Java 語言的區(qū)別很大,Java 語言是一種固定類型語言。在 Groovy 中,類型是可選的,所以您不必輸入 String myStr = "Hello"; 來聲明 String 變量。

除此之外,Groovy 代碼還能在運(yùn)行時(shí)輕松地改變自己。這實(shí)際上意味著,能夠在運(yùn)行時(shí)輕松地為對象指定新方法和屬性。這一編程領(lǐng)域稱為元編程,Groovy 能夠很好地支持這種編程方式。在學(xué)習(xí)本教程的過程中,您將了解到關(guān)于 Groovy 的動態(tài)性質(zhì)的更多內(nèi)容?,F(xiàn)在惟一要補(bǔ)充的是,您會驚訝地發(fā)現(xiàn),在 Groovy 會使操作 XML 或普通的 java.io.File 實(shí)例變得非常輕松。

一體兩面

用 Groovy 編寫的任何內(nèi)容都可以編譯成標(biāo)準(zhǔn)的 Java 類文件并在 Java 代碼中重用。類似地,用標(biāo)準(zhǔn) Java 代碼編寫的內(nèi)容也可以在 Groovy 中重用。所以,可以輕易地使用 Groovy 為 Java 代碼編寫單元測試。而且,如果用 Groovy 編寫一個(gè)方便的小工具,那么也可以在 Java 程序中使用這個(gè)小工具。

回頁首

Groovy 初探

學(xué)習(xí)新語言并不是件小事,即使是 Groovy 也不例外。這一節(jié)將介紹學(xué)習(xí) Groovy 的更多動力。另外還將第一次看到一些 Groovy 代碼,并了解 Groovy 與 Java 編程的比較。

為什么要學(xué)習(xí) Groovy?

即使 Groovy 與 Java 語言有許多相似之處,它仍然是另一個(gè)語言。您可能想知道為什么應(yīng)該花時(shí)間學(xué)習(xí)它。簡單的回答就是:Groovy 是一種更有生產(chǎn)力 的語言。它具有松散的語法和一些特殊功能,能夠加快編碼速度。

只用一個(gè)示例即可說明問題:一旦發(fā)現(xiàn)使用 Groovy 在集合中導(dǎo)航的容易程度,您就再也不會用 Java 處理集合導(dǎo)航了。能夠用 Groovy 快速編寫代碼,這還意味著能夠更快地收到反饋,更不用說完成任務(wù)列表中的工作帶來的滿足感了。在較高層面上,如果能更快地將代碼交付給利益相關(guān)者,那么就能在更短的時(shí)間內(nèi)交給他們更多發(fā)行版。實(shí)際上,Groovy 比 Java 更有助于敏捷開發(fā)。

入門非常容易

如果仍然覺得采用新語言很困難,那么可以看看將 Groovy 集成到開發(fā)環(huán)境有多么容易。您無需安裝新的運(yùn)行時(shí)工具或?qū)iT的 IDE。實(shí)際上,只需將 Groovy 的一個(gè) jar 文件放在類路徑中即可。

而且,Groovy 是一種開源語言,由熱心的 Java 開發(fā)人員社區(qū)管理。因?yàn)?Groovy 獲得 Apache Software License, Version 2.0,所以可以自由地使用它開發(fā)自由軟件和私有軟件。

Groovy 和 Java 語言對比

買車的時(shí)候,如果不試駕一下,是不會買的。所以,在要求您安裝 Groovy 之前,我會演示一些代碼。首先,回顧一下用 Java 如何創(chuàng)建、編譯和運(yùn)行標(biāo)準(zhǔn)的 Hello World 示例;然后再看看如何使用 Groovy 代碼執(zhí)行同一過程。比較這兩個(gè)示例,很容易就能看到這兩種語言之間的差異。

用 Java 編寫的 Hello World

用 Java 編寫的典型的 Hello World 示例如下所示:

public class HelloWorld {  public static void main(String[] args) {		System.out.println("Hello World!");  }}

編譯和運(yùn)行 Java 示例

在這個(gè)簡單的 HelloWorld 類中,我省略了包,而且向控制臺輸出的時(shí)候沒有使用任何多余的編碼約定。下一步是用 javac 編譯這個(gè)類,如下所示:

c:>javac HelloWorld.java

最后,運(yùn)行經(jīng)過編譯的類:

c:>java HelloWorld

迄今為止還不錯(cuò) — 很久以前就會編這么基礎(chǔ)的代碼了,所以這里只是回顧一下。下面,請看用 Groovy 編碼的相同過程。

用 Groovy 編寫的 Hello World

就像前面提到過的,Groovy 支持松散的 Java 語法 — 例如,不需要為打印 “Hello World!” 這樣的簡單操作定義類。

而且,Groovy 使日常的編碼活動變得更容易,例如,Groovy 允許輸入 println,而無需輸入 System.out.println。當(dāng)您輸入 println 時(shí),Groovy 會非常聰明地知道您指的是 System.out。

所以,用 Groovy 編寫 Hello World 程序就如下面這樣簡單:

println "Hello World!"

請注意,在這段代碼周圍沒有類結(jié)構(gòu),而且也沒有方法結(jié)構(gòu)!我還使用 println 代替了 System.out.println。

運(yùn)行 Groovy 示例

假設(shè)我將代碼保存在文件 MyFirstExample.groovy 內(nèi),只要輸入以下代碼就能運(yùn)行這個(gè)示例:

c:>groovy MyFirstExample.groovy

在控制臺上輸出 “Hello World!” 所需的工作就這么多。

快捷方式應(yīng)用

您可能注意到了,我不必編譯 .groovy 文件。這是因?yàn)?Groovy 屬于腳本語言。腳本語言的一個(gè)特點(diǎn)就是能夠在運(yùn)行時(shí)進(jìn)行解釋。(在 Java 中,要從源代碼編譯生成字節(jié)碼,然后才能進(jìn)行解釋。區(qū)別在于腳本語言能夠直接 解釋源代碼。)

Groovy 允許完全省略編譯步驟,不過仍然可以 進(jìn)行編譯。如果想要編譯代碼,可以使用 Groovy 編譯器 groovyc。用 groovyc 編譯 Groovy 代碼會產(chǎn)生標(biāo)準(zhǔn)的 Java 字節(jié)碼,然后可以通過 java 命令運(yùn)行生成的字節(jié)碼。這是 Groovy 的一項(xiàng)經(jīng)常被忽略的關(guān)鍵特性:用 Groovy 編寫的所有代碼都能夠通過標(biāo)準(zhǔn) Java 運(yùn)行時(shí)編譯和運(yùn)行。

至于運(yùn)行代碼,如果我希望更加簡潔,我甚至還能輸入

c:>groovy -e "println 'Hello World!'"

這會生成相同的結(jié)果,而且甚至無需定義任何文件!

回頁首

Groovy 入門

在這一節(jié)中,將真正開始進(jìn)行 Groovy 編程。首先,學(xué)習(xí)如何輕松地安裝 Groovy(通過 Eclipse Groovy 插件),然后從一些有助于了解 Groovy 的簡單示例開始。

輕松安裝 Groovy

為了迅速開始使用 Groovy,需要做的全部工作就是安裝 Eclipse 的 Groovy 插件。打開 Ecliplse,在 Help 菜單中選擇 Software Updates > Find and Install...。

圖 1 顯示了執(zhí)行以上步驟之后出現(xiàn)的對話框:

圖 1. Eclipse Feature Updates 對話框

在選項(xiàng)中導(dǎo)航

接下來,出現(xiàn)一個(gè)對話框,里面包含兩個(gè)選項(xiàng)。請選擇 Search for new features to install 單選按鈕。單擊 Next 按鈕,然后選擇 New Remote Site...。出現(xiàn)一個(gè)新的對話框,里面包含兩個(gè)需要填寫的字段:新位置的名稱和該位置的 URL,如圖 2 所示:

圖 2. 確保為新的遠(yuǎn)程站點(diǎn)提供了正確的 URL

輸入 “Groovy plugin” 作為名稱,輸入 “http://dist.codehaus.org/groovy/distributions/update/” 作為位置,單擊 OK 按鈕,在隨后出現(xiàn)的 Sites to include in search 框中確保選中了名為 “Groovy plugin” 的項(xiàng)目 — 現(xiàn)在的列表應(yīng)該如圖 3 所示。

圖 3.Eclipse 中的遠(yuǎn)程網(wǎng)站清單

完成安裝

單擊 Finish 按鈕之后,應(yīng)該會出現(xiàn) Search Results 對話框。請?jiān)俅未_定選中了 “Groovy plugin” 框并單擊 Next 按鈕,這一步驟如圖 4 所示:

圖 4. 選擇 Groovy 插件

經(jīng)過一系列確認(rèn)之后,將會下載插件,然后可能需要重新啟動 Eclipse。

創(chuàng)建 Groovy 項(xiàng)目

Eclipse 重啟之后,就能夠創(chuàng)建第一個(gè) Groovy 項(xiàng)目了。請確保創(chuàng)建兩個(gè)源文件夾 — 一個(gè)稱為 “groovy”,另一個(gè)稱為 “java”。編寫的 Groovy 代碼放在 groovy 文件夾,Java 代碼放在 java 文件夾。我發(fā)現(xiàn)將二者分開將會很有用,如圖 5 所示:

圖 5. 兩個(gè)源文件夾 — Java 和 Groovy

將 Groovy 導(dǎo)入項(xiàng)目

項(xiàng)目創(chuàng)建之后,右鍵單擊項(xiàng)目的圖標(biāo),應(yīng)該會看到一個(gè) Groovy 選項(xiàng),如圖 6 所示。請選擇該選項(xiàng),然后選擇 Add Groovy Nature 選項(xiàng)。這樣做可以將必要的 Groovy 庫、編譯器和運(yùn)行程序?qū)氲巾?xiàng)目中。

圖 6. 在 Eclipse 中添加 Groovy 特性

創(chuàng)建 Groovy 類

創(chuàng)建 Groovy 類很簡單。選擇 groovy 文件夾并右鍵單擊它。選擇 New,然后選擇 Other,如圖 7 所示:

圖 7. 通過 New 菜單創(chuàng)建 Groovy 類

給類命名

在這里,找到 Groovy 文件夾,并選擇 Groovy Class— 應(yīng)該會看到一個(gè)對話框,如圖 8 所示。

圖 8.選擇創(chuàng)建 Groovy 類

單擊 Next 按鈕,系統(tǒng)將要求您提供類的名稱。輸入 HelloWorld。

現(xiàn)在可以將 HelloWorld Groovy 類保留在默認(rèn)包內(nèi),如圖 9 所示。

圖 9. 現(xiàn)在不必考慮包的問題!

雖然步驟看起來很多,但這與創(chuàng)建標(biāo)準(zhǔn)的 Java 類并沒有什么區(qū)別。

Hello World! — 用 Groovy 編寫的 Java 程序

單擊 Finish 按鈕,應(yīng)該會看到如下所示的代碼段:

class HelloWorld { static void main(args) {		 }}

這看起來同前面的 Java HelloWorld 示例驚人地相似。但是請注意,它不包含 public 修改符。而且,如果仔細(xì)查看 main 方法的參數(shù),會注意到它沒有類型。

編譯程序

現(xiàn)在在 main 方法內(nèi)加入 println "Hello World",完成后的代碼看起來如下所示:

class HelloWorld { static void main(args) {   println "Hello World"	 }}

在源代碼編輯器中應(yīng)該能夠右鍵單擊,并選擇 Compile Groovy File 選項(xiàng),如圖 10 所示。

圖 10. 右鍵單擊 Groovy 文件即可進(jìn)行編譯

運(yùn)行程序

接下來,再次右鍵單擊文件,選擇 Run As 選項(xiàng),然后選擇 Groovy 選項(xiàng)。在 Eclipse 控制臺中應(yīng)該會看到輸出的 “Hello World”,如圖 11 所示。

圖 11. 輸出的 Hello World

學(xué)到了什么?

OK,那么這是一種突出重點(diǎn)的取巧方式。Groovy 實(shí)際上就是 Java。其語法不同 — 多數(shù)情況下會短一些 — 但 Groovy 代碼 100% 符合 Java 字節(jié)碼標(biāo)準(zhǔn)。下一節(jié)將進(jìn)一步介紹這兩種語言的交叉。

回頁首

Groovy 變身為 Java

前面已經(jīng)看到 Groovy 與 Java 代碼實(shí)際上可以互換的第一個(gè)證據(jù)。這一節(jié)將進(jìn)一步證明這點(diǎn),繼續(xù)使用 Groovy 構(gòu)建的 HelloWorld 類。

Hello, Java!

為了使您確信 Groovy 就是 Java,現(xiàn)在在 HelloWorld 類聲明和方法聲明前面加上 public 修改符,如下所示:

public class HelloWorld { public static void main(args) {  println "Hello World" }}

還不確信?

這個(gè)代碼運(yùn)行起來同前面的代碼完全一樣。但是,如果仍不確信,還可以在 args 參數(shù)前加上 String[]

public class HelloWorld { public static void main(String[]args) {  println "Hello World" }}

現(xiàn)在還沒完

現(xiàn)在,還可以將 println 替換為 System.out.println— 而且不要忘記加上括號。

public class HelloWorld { public static void main(String[] args) {  System.out.println("Hello World")  }}

現(xiàn)在的代碼與前面用 Java 編寫的 Hello World 示例完全相同,但是哪個(gè)示例更容易編寫呢?

請注意,原來的基于 Groovy 的 HelloWorld 類沒有任何 public 修改符,沒有任何類型(沒有 String[]),而且提供了沒有括號的 println 快捷方式。

Hello, Groovy!

如果喜歡,可以將這個(gè)過程完全翻轉(zhuǎn)過來,回到基于 Java 的 Hello World 示例,刪除文件里的所有內(nèi)容,只保留 System.out 行,然后在這行刪除 System.out 和括號。最后只剩下:

println "Hello World"

現(xiàn)在,哪個(gè)程序更容易編寫呢?

運(yùn)行程序!

Groovy 代碼完全符合 Java 字節(jié)碼標(biāo)準(zhǔn),這個(gè)練習(xí)證明了這一點(diǎn)。在 Eclipse 中,選擇 Run 菜單選項(xiàng) Open Run Dialog...。選擇一個(gè)新的 Java Application 配置。確保項(xiàng)目是您的 Groovy 項(xiàng)目。對于 Main 類,單擊 Search 按鈕,找到 HelloWorld 類。請注意,單詞 class 表明 Eclipse Groovy 插件已經(jīng)將 .groovy 文件編譯為 .class 文件。

在圖 12 中可以看到整個(gè)這個(gè)過程 — 如果以前在 Eclipse 中運(yùn)行過 Java 類,那么您應(yīng)該對這個(gè)過程很熟悉。

圖 12. Groovy 代碼完全符合 Java 字節(jié)碼標(biāo)準(zhǔn)

單擊 Run 按鈕,看到什么了?實(shí)際上,“Hello World!” 從未像現(xiàn)在這樣能夠說明問題。

回頁首

Groovy 是沒有類型的 Java 代碼

很可能將 Groovy 當(dāng)成是沒有規(guī)則的 Java 代碼。但實(shí)際上,Groovy 只是規(guī)則少一些。這一節(jié)的重點(diǎn)是使用 Groovy 編寫 Java 應(yīng)用程序時(shí)可以不用考慮的一個(gè) Java 編程的具體方面:類型定義。

為什么要有類型定義?

在 Java 中,如果要聲明一個(gè) String 變量,則必須輸入:

String value = "Hello World";

但是,如果仔細(xì)想想,就會看出,等號右側(cè)的字符已經(jīng)表明 value 的類型是 String。所以,Groovy 允許省略 value 前面的 String 類型變量,并用 def 代替。

def value = "Hello World"

實(shí)際上,Groovy 會根據(jù)對象的值來判斷它的類型。

運(yùn)行程序!

將 HelloWorld.groovy 文件中的代碼編輯成下面這樣:

String message = "Hello World"println message

運(yùn)行這段代碼,應(yīng)該會在控制臺上看到與前面一樣的 “Hello World”?,F(xiàn)在,將變量類型 String 替換為 def 并重新運(yùn)行代碼。是不是注意到了相同的結(jié)果?

除了輸出 message 的值,還可以用以下調(diào)用輸出它的類型:

def message = "Hello World"println message.class

輸出 “class java.lang.String” 應(yīng)該是目前為止很受歡迎的一項(xiàng)變化!如果想知道到底發(fā)生了什么,那么可以告訴您:Groovy 推斷出 message 一定是 String 類型的,因?yàn)樗闹凳怯秒p引號括起來的。

類型推斷的更多內(nèi)容

您可能聽說過,在 Groovy 中 “一切都是對象” — 但對于類型來說這句話意味著什么呢?讓我們看看如果將前面示例中的 String 替換為數(shù)字會怎么樣,如下所示:

def message = 12println message.class

message 變量的數(shù)字值看起來像是 Java 的原生類型 int。但是,運(yùn)行這個(gè)代碼就可以看出,Groovy 將它作為 Integer。這是因?yàn)樵?Groovy 中 “一切都是對象”。

Java 中的所有對象都擴(kuò)展自 java.lang.Object,這對 Groovy 來說非常方便。即使在最糟的情況下,Groovy 運(yùn)行時(shí)不能確定變量的類型,它只需將變量當(dāng)成 Object,問題就解決了。

繼續(xù)使用這段代碼。將 message 改成自己喜歡的任意類型:Groovy 會在運(yùn)行時(shí)盡其所能推斷出這個(gè)變量的類型。

無類型有什么意義

那么,Groovy 缺少類型意味著所需的輸入更少。不可否認(rèn),將 String 替換成 def 并沒有真正節(jié)約多少打字工作 — 三個(gè)字母并不值得如何夸耀!但是在更高的層次上看,在編寫大量不僅僅包含變量聲明的代碼的時(shí)候,沒有類型確實(shí)減少了許多打字工作。更重要的是,這意味著要閱讀的代碼要少得多。最后,Groovy 缺少類型能夠帶來更高的靈活性 — 不需要接口或抽象類。

所以,只需要使用 def 關(guān)鍵字就能在方法中聲明一個(gè)獨(dú)立變量,不需要將 def 關(guān)鍵字作為方法聲明中的參數(shù)。在 for 循環(huán)聲明中也不需要它,這意味著不用編寫 (int x = 0; x < 5; x++),相反,可以省略 int,保留空白。

回頁首

通過 Groovy 進(jìn)行循環(huán)

同大多數(shù)腳本語言一樣,Groovy 經(jīng)常被宣傳為生產(chǎn)力更高 的 Java 語言替代品。您已經(jīng)看到了 Groovy 缺少類型能夠如何減少打字工作。在這一節(jié),將創(chuàng)建并試用一個(gè) repeat 函數(shù)。在這個(gè)過程中,將進(jìn)一步探索 Groovy 提高效率的方式。

更好、更短的循環(huán)

下面這種方法可以更好地感受 Groovy 缺乏類型的好處:首先,用與創(chuàng)建 HelloWorld 相同的方式創(chuàng)建一個(gè) Groovy 類,將這個(gè)類稱為 MethodMadness,并刪除自動生成的類體:將要定義一個(gè)獨(dú)立的 repeat 函數(shù)?,F(xiàn)在在控制臺中輸入以下代碼:

def repeat(val){ for(i = 0; i < 5; i++){  println val }}

起初,從 Java 的角度來看,這個(gè)小函數(shù)看起來可能有些怪(實(shí)際上,它很像 JavaScript)。但它就是 Java 代碼,只不過是用 Groovy 的樣式編寫的。

深入方法

repeat 函數(shù)接受一個(gè)變量 val。請注意參數(shù)不需要 def。方法體本質(zhì)上就是一個(gè) for 循環(huán)。

調(diào)用這個(gè)函數(shù)。

repeat("hello  world")

會輸出 “hello world” 五次。請注意,for 循環(huán)中省略了 int。沒有變量類型的 for 循環(huán)要比標(biāo)準(zhǔn)的 Java 代碼短些?,F(xiàn)在看看如果在代碼里加入范圍會出現(xiàn)什么情況。

Groovy 中的范圍

范圍 是一系列的值。例如 “0..4” 表明包含 整數(shù) 0、1、2、3、4。Groovy 還支持排除范圍,“0..<4” 表示 0、1、2、3。還可以創(chuàng)建字符范圍:“a..e” 相當(dāng)于 a、b、c、d、e?!?code>a..<e” 包括小于 e 的所有值。

循環(huán)范圍

范圍為循環(huán)帶來了很大的方便。例如,前面從 0 遞增到 4 的 for 循環(huán)如下所示:

for(i = 0; i < 5; i++)

范圍可以將這個(gè) for 循環(huán)變得更簡潔,更易閱讀:

def repeat(val){ for(i in 0..5){  println val }}

設(shè)置范圍

如果運(yùn)行這個(gè)示例,可能會注意到一個(gè)小問題:“Hello World” 輸出了六次而不是五次。這個(gè)問題有三種解決方法:

  • 將包含的范圍限制到 4:
    for(i in 0..4)
  • 從 1 而不是 0 開始:
    def repeat(val){ for(i in 1..5){  println val }}
  • 將范圍由包含改為排除:
    def repeat(val){ for(i in 0..<5){  println val }}

不論采用哪種方法,都會得到原來的效果 — 輸出 “Hello World” 五次。

默認(rèn)參數(shù)值

現(xiàn)在已經(jīng)成功地使用 Groovy 的范圍表達(dá)式縮短了 repeat 函數(shù)。但這個(gè)函數(shù)依然有些限制。如果想重復(fù) “Hello World” 八次該怎么辦?如果想對不同的值重復(fù)不同次數(shù) — 比如 “Hello World” 重復(fù)八次,“Goodbye Sunshine” 重復(fù)兩次,這時(shí)該怎么辦?

每次調(diào)用 repeat 時(shí)都要指定需要的重復(fù)次數(shù)的做法已經(jīng)過時(shí)了,特別是在已經(jīng)適應(yīng)了默認(rèn)行為(重復(fù)五次)的時(shí)候。

Groovy 支持默認(rèn)參數(shù)值,可以在函數(shù)或方法的正式定義中指定參數(shù)的默認(rèn)值。調(diào)用函數(shù)的程序可以選擇省略參數(shù),使用默認(rèn)值。

更加復(fù)雜的參數(shù)值

使用前面的 repeat 函數(shù)時(shí),如果希望調(diào)用程序能夠指定重復(fù)值,可以像下面這樣編碼:

def repeat(val, repeat=5){ for(i in 0..<repeat){  println val }}

像下面這樣調(diào)用該函數(shù):

repeat("Hello World", 2)repeat("Goodbye sunshine", 4)repeat("foo")

結(jié)果會輸出 “Hello World” 兩次,“Goodbye sunshine” 四次,“foo” 五次(默認(rèn)次數(shù))。

回頁首

Groovy 集合

在 Groovy 提供的所有方便的快捷方式和功能中,最有幫助的一個(gè)可能就是內(nèi)置的 集合?;叵胍幌略?Java 編程中是如何使用集合的 — 導(dǎo)入 java.util 類,初始化集合,將項(xiàng)加入集合。這三個(gè)步驟都會增加不少代碼。

而 Groovy 可以直接在語言內(nèi)使用集合。在 Groovy 中,不需要導(dǎo)入專門的類,也不需要初始化對象。集合是語言本身的本地成員。Groovy 也使集合(或者列表)的操作變得非常容易,為增加和刪除項(xiàng)提供了直觀的幫助。

可以將范圍當(dāng)作集合

在前一節(jié)學(xué)習(xí)了如何用 Groovy 的范圍將循環(huán)變得更容易。范圍表達(dá)式 “0..4” 代表數(shù)字的集合— 0、1、2、3 和 4。為了驗(yàn)證這一點(diǎn),請創(chuàng)建一個(gè)新類,將其命名為 Ranger。保留類定義和 main 方法定義。但是這次添加以下代碼:

def range = 0..4println range.classassert range instanceof List

請注意,assert 命令用來證明范圍是 java.util.List 的實(shí)例。接著運(yùn)行這個(gè)代碼,證實(shí)該范圍現(xiàn)在是類型 List 的集合。

豐富的支持

Groovy 的集合支持相當(dāng)豐富,而且美妙之處就在于,在 Groovy 的魔法背后,一切都是標(biāo)準(zhǔn)的 Java 對象。每個(gè) Groovy 集合都是 java.util.Collectionjava.util.Map 的實(shí)例。

前面提到過,Groovy 的語法提供了本地列表和映射。例如,請將以下兩行代碼添加到 Ranger 類中:

def coll = ["Groovy", "Java", "Ruby"]assert  coll instanceof Collectionassert coll instanceof ArrayList

你將會注意到,coll 對象看起來很像 Java 語言中的數(shù)組。實(shí)際上,它是一個(gè) Collection。要在普通的 Java 代碼中得到集合的相同實(shí)例,必須執(zhí)行以下操作:

Collection<String> coll = new ArrayList<String>();coll.add("Groovy");coll.add("Java");coll.add("Ruby");

在 Java 代碼中,必須使用 add() 方法向 ArrayList 實(shí)例添加項(xiàng)。

添加項(xiàng)

Groovy 提供了許多方法可以將項(xiàng)添加到列表 — 可以使用 add() 方法(因?yàn)榈讓拥募鲜且粋€(gè)普通的 ArrayList 類型),但是還有許多快捷方式可以使用。

例如,下面的每一行代碼都會向底層集合加入一些項(xiàng):

coll.add("Python")coll << "Smalltalk"coll[5] = "Perl"

請注意,Groovy 支持操作符重載 —<< 操作符被重載,以支持向集合添加項(xiàng)。還可以通過位置參數(shù)直接添加項(xiàng)。在這個(gè)示例中,由于集合中只有四個(gè)項(xiàng),所以 [5] 操作符將 “Perl” 放在最后。請自行輸出這個(gè)集合并查看效果。

檢索非常輕松

如果需要從集合中得到某個(gè)特定項(xiàng),可以通過像上面那樣的位置參數(shù)獲取項(xiàng)。例如,如果想得到第二個(gè)項(xiàng) “Java”,可以編寫下面這樣的代碼(請記住集合和數(shù)組都是從 0 開始):

assert coll[1] == "Java"

Groovy 還允許在集合中增加或去掉集合,如下所示:

def numbers = [1,2,3,4]assert numbers + 5 == [1,2,3,4,5]assert numbers - [2,3] == [1,4]

請注意,在上面的代碼中, 實(shí)際上創(chuàng)建了新的 集合實(shí)例,由最后一行可以看出。

魔法方法

Groovy 還為集合添加了其他一些方便的功能。例如,可以在集合實(shí)例上調(diào)用特殊的方法,如下所示:

def numbers = [1,2,3,4]assert numbers.join(",") == "1,2,3,4" assert [1,2,3,4,3].count(3) == 2

join()count() 只是在任何項(xiàng)列表上都可以調(diào)用的眾多方便方法中的兩個(gè)。分布操作符(spread operator) 是個(gè)特別方便的工具,使用這個(gè)工具不用在集合上迭代,就能夠調(diào)用集合的每個(gè)項(xiàng)上的方法。

假設(shè)有一個(gè) String 列表,現(xiàn)在想將列表中的項(xiàng)目全部變成大寫,可以編寫以下代碼:

assert ["JAVA", "GROOVY"] ==   ["Java", "Groovy"]*.toUpperCase()

請注意 *. 標(biāo)記。對于以上列表中的每個(gè)值,都會調(diào)用 toUpperCase(),生成的集合中每個(gè) String 實(shí)例都是大寫的。

回頁首

Groovy 映射

除了豐富的列表處理功能,Groovy 還提供了堅(jiān)固的映射機(jī)制。同列表一樣,映射也是本地?cái)?shù)據(jù)結(jié)構(gòu)。而且 Groovy 中的任何映射機(jī)制在幕后都是 java.util.Map 的實(shí)例。

Java 語言中的映射

Java 語言中的映射是名稱-值對的集合。所以,要用 Java 代碼創(chuàng)建典型的映射,必須像下面這樣操作:

Map<String, String>map = new HashMap<String, String>();map.put("name", "Andy");map.put("VPN-#","45");

一個(gè) HashMap 實(shí)例容納兩個(gè)名稱-值對,每一個(gè)都是 String 的實(shí)例。

通過 Groovy 進(jìn)行映射

Groovy 使得處理映射的操作像處理列表一樣簡單 — 例如,可以用 Groovy 將上面的 Java 映射寫成

def hash = [name:"Andy", "VPN-#":45]

請注意,Groovy 映射中的鍵不必是 String。在這個(gè)示例中,name 看起來像一個(gè)變量,但是在幕后,Groovy 會將它變成 String。

全都是 Java

接下來創(chuàng)建一個(gè)新類 Mapper 并加入上面的代碼。然后添加以下代碼,以證實(shí)底層的代碼是真正的 Java 代碼:

assert hash.getClass() == java.util.LinkedHashMap

可以看到 Groovy 使用了 Java 的 LinkedHashMap 類型,這意味著可以使用標(biāo)準(zhǔn)的 Java 一樣語句對 hash 中的項(xiàng)執(zhí)行 putget 操作。

hash.put("id", 23)assert hash.get("name") == "Andy"

有 groovy 特色的映射

現(xiàn)在您已經(jīng)看到,Groovy 給任何語句都施加了魔法,所以可以用 . 符號將項(xiàng)放入映射中。如果想將新的名稱-值對加入映射(例如 dob 和 “01/29/76”),可以像下面這樣操作:

hash.dob = "01/29/76"

. 符號還可以用來獲取項(xiàng)。例如,使用以下方法可以獲取 dob 的值:

assert hash.dob == "01/29/76"

當(dāng)然 . 要比調(diào)用 get() 方法更具 Groovy 特色。

位置映射

還可以使用假的位置語法將項(xiàng)放入映射,或者從映射獲取項(xiàng)目,如下所示:

assert hash["name"] == "Andy"hash["gender"] = "male"assert hash.gender == "male"assert hash["gender"] == "male"

但是,請注意,在使用 [] 語法從映射獲取項(xiàng)時(shí),必須將項(xiàng)作為 String 引用。

回頁首

Groovy 中的閉包

現(xiàn)在,閉包是 Java 世界的一個(gè)重大主題,對于是否會在 Java 7 中包含閉包仍然存在熱烈的爭論。有些人會問:既然 Groovy 中已經(jīng)存在閉包,為什么 Java 語言中還需要閉包?這一節(jié)將學(xué)習(xí) Groovy 中的閉包。如果沒有意外,在閉包成為 Java 語法的正式部分之后,這里學(xué)到的內(nèi)容將給您帶來方便。

不再需要更多迭代

雖然在前幾節(jié)編寫了不少集合代碼,但還沒有實(shí)際地在集合上迭代。當(dāng)然,您知道 Groovy 就是 Java,所以如果愿意,那么總是能夠得到 Java 的 Iterator 實(shí)例,用它在集合上迭代,就像下面這樣:

def acoll = ["Groovy", "Java", "Ruby"]		for(Iterator iter = acoll.iterator(); iter.hasNext();){ println iter.next()}

實(shí)際上在 for 循環(huán)中并不需要類型聲明,因?yàn)?Groovy 已經(jīng)將迭代轉(zhuǎn)變?yōu)槿魏渭系闹苯映蓡T。在這個(gè)示例中,不必獲取 Iterator 實(shí)例并直接操縱它,可以直接在集合上迭代。而且,通常放在循環(huán)構(gòu)造內(nèi)的行為(例如 for 循環(huán)體中 println)接下來要放在閉包內(nèi)。在深入之前,先看看如何執(zhí)行這步操作。

能否看見閉包?

對于上面的代碼,可以用更簡潔的方式對集合進(jìn)行迭代,如下所示:

def acoll = ["Groovy", "Java", "Ruby"]		acoll.each{ println it}

請注意,each 直接在 acoll 實(shí)例內(nèi)調(diào)用,而 acoll 實(shí)例的類型是 ArrayList。在 each 調(diào)用之后,引入了一種新的語法 —{,然后是一些代碼,然后是 }。由 {} 包圍起來的代碼塊就是閉包。

執(zhí)行代碼

閉包是可執(zhí)行的代碼塊。它們不需要名稱,可以在定義之后執(zhí)行。所以,在上面的示例中,包含輸出 it(后面將簡單解釋 it)的行為的無名閉包將會在 acoll 集合類型中的每個(gè)值上被調(diào)用。

在較高層面上,{} 中的代碼會執(zhí)行三次,從而生成如圖 13 所示的輸出。

圖 13. 迭代從未像現(xiàn)在這樣容易

閉包中的 it 變量是一個(gè)關(guān)鍵字,指向被調(diào)用的外部集合的每個(gè)值 — 它是默認(rèn)值,可以用傳遞給閉包的參數(shù)覆蓋它。下面的代碼執(zhí)行同樣的操作,但使用自己的項(xiàng)變量:

def acoll = ["Groovy", "Java", "Ruby"]		acoll.each{ value -> println value}

在這個(gè)示例中,用 value 代替了 Groovy 的默認(rèn) it。

迭代無處不在

閉包在 Groovy 中頻繁出現(xiàn),但是,通常用于在一系列值上迭代的時(shí)候。請記住,一系列值可以用多種方式表示,不僅可以用列表表示 — 例如,可以在映射、String、JDBC Rowset、File 的行上迭代,等等。

如果想在前面一節(jié) “Groovy 中的映射” 中的 hash 對象上迭代,可以編寫以下代碼:

def hash = [name:"Andy", "VPN-#":45]hash.each{ key, value -> println "${key} : ${value}"}

請注意,閉包還允許使用多個(gè)參數(shù) — 在這個(gè)示例中,上面的代碼包含兩個(gè)參數(shù)(keyvalue)。

使用 Java 代碼迭代

以下是使用典型的 Java 構(gòu)造如何進(jìn)行同樣的迭代:

Map<String, String>map = new HashMap<String, String>();map.put("name", "Andy");map.put("VPN-#","45");				for(Iterator iter = map.entrySet().iterator(); iter.hasNext();){ Map.Entry entry = (Map.Entry)iter.next(); System.out.println(entry.getKey() + " : " + entry.getValue());}

上面的代碼比 Groovy 的代碼長得多,是不是?如果要處理大量集合,那么顯然用 Groovy 處理會更方便。

迭代總結(jié)

請記住,凡是集合或一系列的內(nèi)容,都可以使用下面這樣的代碼進(jìn)行迭代。

"ITERATION".each{ println it.toLowerCase()}

閉包的更多使用方式

雖然在迭代上使用閉包的機(jī)會最多,但閉包確實(shí)還有其他用途。因?yàn)殚]包是一個(gè)代碼塊,所以能夠作為參數(shù)進(jìn)行傳遞(Groovy 中的函數(shù)或方法不能這樣做)。閉包在調(diào)用的時(shí)候才會執(zhí)行這一事實(shí)(不是在定義的時(shí)候)使得它們在某些場合上特別有用。

例如,通過 Eclipse 創(chuàng)建一個(gè) ClosureExample 對象,并保持它提供的默認(rèn)類語法。在生成的 main() 方法中,添加以下代碼:

def excite = { word -> return "${word}!!"}

這段代碼是名為 excite 的閉包。這個(gè)閉包接受一個(gè)參數(shù)(名為 word),返回的 Stringword 變量加兩個(gè)感嘆號。請注意在 String 實(shí)例中替換 的用法。在 String 中使用 ${value}語法將告訴 Groovy 替換 String 中的某個(gè)變量的值??梢詫⑦@個(gè)語法當(dāng)成 return word + "!!" 的快捷方式。

延遲執(zhí)行

既然有了閉包,下面就該實(shí)際使用它了??梢酝ㄟ^兩種方法調(diào)用閉包:直接調(diào)用或者通過 call() 方法調(diào)用。

繼續(xù)使用 ClosureExample 類,在閉包定義下面添加以下兩行代碼:

assert "Groovy!!" == excite("Groovy")assert "Java!!" == excite.call("Java")

可以看到,兩種調(diào)用方式都能工作,但是直接調(diào)用的方法更簡潔。不要忘記閉包在 Groovy 中也是一類對象 — 既可以作為參數(shù)傳遞,也可以放在以后執(zhí)行。用普通的 Java 代碼可以復(fù)制同樣的行為,但是不太容易。現(xiàn)在不會感到驚訝了吧?

回頁首

Groovy 中的類

迄今為止,您已經(jīng)用 Groovy 輸出了許多次 “Hello World”,已經(jīng)操作了集合,用閉包在集合上迭代,也定義了您自己的閉包。做所有這些工作時(shí),甚至還沒有討論那個(gè)對 Java 開發(fā)人員來說至關(guān)重要的概念 — 類。

當(dāng)然,您已經(jīng)在這個(gè)教程中使用過類了:您編寫的最后幾個(gè)示例就是在不同類的 main() 方法中。而且,您已經(jīng)知道,在 Groovy 中可以像在 Java 代碼中一樣定義類。惟一的區(qū)別是,不需要使用 public 修改符,而且還可以省略方法參數(shù)的類型。這一節(jié)將介紹使用 Groovy 類能夠進(jìn)行的其他所有操作。

Song 類

我們先從用 Groovy 定義一個(gè)簡單的 JavaBean 形式的類開始,這個(gè)類稱為Song

第一步自然是用 Groovy 創(chuàng)建名為 Song 的類。這次還要為它創(chuàng)建一個(gè)包結(jié)構(gòu) — 創(chuàng)建一個(gè)包名,例如 org.acme.groovy

創(chuàng)建這個(gè)類之后,刪除 Groovy 插件自動生成的 main()

歌曲有一些屬性 — 創(chuàng)作歌曲的藝術(shù)家、歌曲名稱、風(fēng)格等等。請將這些屬性加入新建的 Song 類,如下所示:

package org.acme.groovyclass Song { def name def artist def genre}

迄今為止還不錯(cuò),是不是?對于 Grooovy 的新開發(fā)人員來說,還不算太復(fù)雜!

Groovy 類就是 Java 類

應(yīng)該還記得本教程前面說過 Groovy 編譯器為用 Groovy 定義的每個(gè)類都生成標(biāo)準(zhǔn)的 Java .class。還記得如何用 Groovy 創(chuàng)建 HelloWorld 類、找到 .class 文件并運(yùn)行它么?也可以用新定義的 Song 類完成同樣的操作。如果通過 Groovy 的 groovyc 編譯器編譯代碼(Eclipse Groovy 插件已經(jīng)這樣做了),就會生成一個(gè) Song.class 文件。

這意味著,如果想在另一個(gè) Groovy 類或 Java 類中使用新建的 Song 類,則必須導(dǎo)入 它(當(dāng)然,除非使用 Song 的代碼與 Song 在同一個(gè)包內(nèi))。

接下來創(chuàng)建一個(gè)新類,名為 SongExample,將其放在另一個(gè)包結(jié)構(gòu)內(nèi),假設(shè)是 org.thirdparty.lib

現(xiàn)在應(yīng)該看到如下所示的代碼:

package org.thirdparty.libclass SongExample { static void main(args) {}}

類的關(guān)系

現(xiàn)在是使用 Song 類的時(shí)候了。首先導(dǎo)入實(shí)例,并將下面的代碼添加到 SongExamplemain() 方法中。

package org.thirdparty.libimport org.acme.groovy.Songclass SongExample { static void main(args) {  def sng = new Song(name:"Le Freak",     artist:"Chic", genre:"Disco") }}

現(xiàn)在 Song 實(shí)例創(chuàng)建完成了!但是仔細(xì)看看以前定義的 Song 類的初始化代碼,是否注意到什么特殊之處?您應(yīng)該注意到自動生成了構(gòu)造函數(shù)。

類初始化

Groovy 自動提供一個(gè)構(gòu)造函數(shù),構(gòu)造函數(shù)接受一個(gè)名稱-值對的映射,這些名稱-值對與類的屬性相對應(yīng)。這是 Groovy 的一項(xiàng)開箱即用的功能 — 用于類中定義的任何屬性,Groovy 允許將存儲了大量值的映射傳給構(gòu)造函數(shù)。映射的這種用法很有意義,例如,您不用初始化對象的每個(gè)屬性。

也可以添加下面這樣的代碼:

def sng2 = new Song(name:"Kung Fu Fighting", genre:"Disco")

也可以像下面這樣直接操縱類的屬性:

def sng3 = new Song()sng3.name = "Funkytown"sng3.artist = "Lipps Inc."sng3.setGenre("Disco")		assert sng3.getArtist() == "Lipps Inc."

從這個(gè)代碼中明顯可以看出,Groovy 不僅創(chuàng)建了一個(gè)構(gòu)造函數(shù),允許傳入屬性及其值的映射,還可以通過 . 語法間接地訪問屬性。而且,Groovy 還生成了標(biāo)準(zhǔn)的 setter 和 getter 方法。

在進(jìn)行屬性操縱時(shí),非常有 Groovy 特色的是:總是會調(diào)用 setter 和 getter 方法 — 即使直接通過 . 語法訪問屬性也是如此。

核心的靈活性

Groovy 是一種本質(zhì)上就很靈活的語言。例如,看看從前面的代碼中將 setGenre() 方法調(diào)用的括號刪除之后會怎么樣,如下所示:

sng3.setGenre "Disco"assert sng3.genre == "Disco"

在 Groovy 中,對于接受參數(shù)的方法,可以省略括號 — 在某些方面,這樣做會讓代碼更容易閱讀。

方法覆蓋

迄今為止已經(jīng)成功地創(chuàng)建了 Song 類的一些實(shí)例。但是,它們還沒有做什么有趣的事情。可以用以下命令輸出一個(gè)實(shí)例:

println sng3

在 Java 中這樣只會輸出所有對象的默認(rèn) toString() 實(shí)現(xiàn),也就是類名和它的 hashcode(即 org.acme.groovy.Song@44f787)。下面來看看如何覆蓋默認(rèn)的 toString() 實(shí)現(xiàn),讓輸出效果更好。

Song 類中,添加以下代碼:

String toString(){ "${name}, ${artist}, ${genre}"}

根據(jù)本教程已經(jīng)學(xué)到的內(nèi)容,可以省略 toString() 方法上的 public 修改符。仍然需要指定返回類型(String),以便實(shí)際地覆蓋正確的方法。方法體的定義很簡潔 — 但 return 語句在哪?

不需要 return

您可能已經(jīng)想到:在 Groovy 中可以省略 return 語句。Groovy 默認(rèn)返回方法的最后一行。所以在這個(gè)示例中,返回包含類屬性的 String。

重新運(yùn)行 SongExample 類,應(yīng)該會看到更有趣的內(nèi)容。toString() 方法返回一個(gè)描述,而不是 hashcode。

特殊訪問

Groovy 的自動生成功能對于一些功能來說很方便,但有些時(shí)候需要覆蓋默認(rèn)的行為。例如,假設(shè)需要覆蓋 Song 類中 getGenre() 方法,讓返回的 String 全部為大寫形式。

提供這個(gè)新行為很容易,只要定義 getGenre() 方法即可??梢宰尫椒ǖ穆暶鞣祷?String,也可以完全省略它(如果愿意)。下面的操作可能是最簡單的:

def getGenre(){ genre.toUpperCase()}

同以前一樣,這個(gè)簡單方法省略了返回類型和 return 語句。現(xiàn)在再次運(yùn)行 SongExample 類。應(yīng)該會看到一些意外的事情 —— 出現(xiàn)了空指針異常。

空指針安全性

如果您一直在跟隨本教程,那么應(yīng)該已經(jīng)在 SongExample 類中加入了下面的代碼:

assert sng3.genre == "Disco"

結(jié)果在重新運(yùn)行 SongExample 時(shí)出現(xiàn)了斷言錯(cuò)誤 — 這正是為什么在 Eclipse 控制臺上輸出了丑陋的紅色文字。(很抱歉使用了這么一個(gè)糟糕的技巧)

幸運(yùn)的是,可以輕松地修復(fù)這個(gè)錯(cuò)誤:只要在 SongExample 類中添加以下代碼:

println sng2.artist.toUpperCase()

但是現(xiàn)在控制臺上出現(xiàn)了更多的 紅色文本 — 出什么事了?!

可惡的 null

如果回憶一下,就會想起 sng2 實(shí)例沒有定義 artist 值。所以,在調(diào)用 toUpperCase() 方法時(shí)就會生成 Nullpointer 異常。

幸運(yùn)的是, Groovy 通過 操作符提供了一個(gè)安全網(wǎng) — 在方法調(diào)用前面添加一個(gè) 就相當(dāng)于在調(diào)用前面放了一個(gè)條件,可以防止在 null 對象上調(diào)用方法。

例如,將 sng2.artist.toUpperCase() 行替換成 sng2.artist?.toUpperCase()。請注意,也可以省略后面的括號。(Groovy 實(shí)際上也允許在不帶參數(shù)的方法上省略括號。不過,如果 Groovy 認(rèn)為您要訪問類的屬性而不是方法,那么這樣做可能會造成問題。)

重新運(yùn)行 SongExample 類,您會發(fā)現(xiàn) 操作符很有用。在這個(gè)示例中,沒有出現(xiàn)可惡的異常?,F(xiàn)在將下面的代碼放在這個(gè)類內(nèi),再次運(yùn)行代碼。

def sng4 = new Song(name:"Thriller", artist:"Michael Jackson")println sng4

就是 Java

您將會注意到,雖然預(yù)期可能有異常,但是沒有生成異常。即使沒有定義 genre,getGenre() 方法也會調(diào)用 toUpperCase()。

您還記得 Groovy 就是 Java,對吧?所以在 SongtoString() 中,引用了 genre 屬性本身,所以不會調(diào)用 getGenre()?,F(xiàn)在更改 toString() 方法以使用 getGenre(),然后再看看程序運(yùn)行的結(jié)果。

String toString(){ "${name}, ${artist}, ${getGenre()}"}

重新運(yùn)行 SongExample,出現(xiàn)類似的異?!,F(xiàn)在,請自己嘗試修復(fù)這個(gè)問題,看看會發(fā)生什么。

另一個(gè)方便的小操作符

希望您做的修改與我的類似。在下面將會看到,我進(jìn)一步擴(kuò)充了 Song 類的 getGenre() 方法,以利用 Groovy 中方便的 操作符。

def getGenre(){ genre?.toUpperCase()}

操作符時(shí)刻都非常有用,可以極大地減少條件語句。

回頁首

對 Groovy 進(jìn)行單元測試

本教程一直都強(qiáng)調(diào) Groovy 只是 Java 的一個(gè)變體。您已經(jīng)看到可以用 Groovy 編寫并使用標(biāo)準(zhǔn)的 Java 程序。為了最后一次證明這點(diǎn),在結(jié)束本教程之前,我們將通過 JUnit 利用 JavaSong 類進(jìn)行單元測試。

將 JUnit 加入 Eclipse 項(xiàng)目

為了跟上本節(jié)的示例,需要將 JUnit 加入到 Eclipse 項(xiàng)目中。首先,右鍵單擊項(xiàng)目,選擇 Build Path,然后選擇 Add Libraries,如圖 14 所示:

圖 14. 將 JUnit 加入到項(xiàng)目的構(gòu)建路徑

會出現(xiàn) Add Library 對話框,如圖 15 所示。

圖 15. 從庫列表中選擇 JUnit

選擇 JUnit 并單擊 Next 按鈕。應(yīng)該會看到如圖 16 所示的對話框。選擇 JUnit34— 具體選擇哪項(xiàng)全憑自己決定 — 并單擊 Finish 按鈕。

圖 16. 選擇 JUnit 3 或 JUnit 4

設(shè)置新的測試用例

現(xiàn)在在項(xiàng)目的類路徑中加入了 JUnit,所以能夠編寫 JUnit 測試了。請右鍵單擊 java 源文件夾,選擇 New,然后選擇 JUnit Test Case。定義一個(gè)包,給測試用例命名(例如 SongTest),在 Class Under Test 部分,單擊 Browse 按鈕。

請注意,可以選擇用 Groovy 定義的 Song 類。圖 17 演示了這一步驟:

圖 17.找到 Song 類

選擇該類并單擊 OK(應(yīng)該會看到與圖 18 類似的對話框)并在 New JUnit Test Case 對話框中單擊 Finish 按鈕。

圖 18. Song 的新測試用例

定義測試方法

我選擇使用 JUnit 4;所以我定義了一個(gè)名為 testToString() 的測試方法,如下所示:

package org.acme.groovy;import org.junit.Test;public class SongTest {	 @Test public void testToString(){}}

測試 toString

顯然,需要驗(yàn)證 toString() 方法是否沒有問題,那么第一步該做什么呢?如果想的是 “導(dǎo)入 Song 類”,那么想得就太難了 —Song 類在同一個(gè)包內(nèi),所以第一步是創(chuàng)建它的實(shí)例。

在創(chuàng)建用于測試的 Song 實(shí)例時(shí),請注意不能通過傳給構(gòu)造函數(shù)的映射完全初始化 — 而且,如果想自動完成實(shí)例的 setter 方法,可以看到每個(gè) setter 接受的是 Object 而不是 String(如圖 19 所示)。為什么會這樣呢?

圖 19. 所有的 setter 和 getter

Groovy 的功勞

如果回憶一下,就會記得我在本教程開始的時(shí)候說過:

因?yàn)?Java 中的每個(gè)對象都擴(kuò)展自 java.lang.Object,所以即使在最壞情況下,Groovy 不能確定變量的類型,Groovy 也能將變量的類型設(shè)為 Object然后問題就會迎刃而解。

現(xiàn)在回想一下,在定義 Song 類時(shí),省略了每個(gè)屬性的類型。Groovy 將自然地將每個(gè)屬性的類型設(shè)為 Object。所以,在標(biāo)準(zhǔn) Java 代碼中使用 Song 類時(shí),看到的 getter 和 setter 的參數(shù)類型和返回類型全都是 Object。

修正返回類型

為了增添樂趣,請打開 Groovy Song 類,將 artist 屬性改為 String 類型,而不是無類型,如下所示:

package org.acme.groovyclass Song { def name String artist def genre	 String toString(){  "${name}, ${artist}, ${getGenre()}" }	 def getGenre(){  genre?.toUpperCase() }}

現(xiàn)在,回到 JUnit 測試,在 Song 實(shí)例上使用自動完成功能 — 看到了什么?

在圖 20 中(以及您自己的代碼中,如果一直跟隨本教程的話),setArtist() 方法接受一個(gè) String,而不是Object。Groovy 再次證明了它就是 Java,而且應(yīng)用了相同的規(guī)則。

圖 20. String,而不是 object

始終是普通的 Java

返回來編寫測試,另外請注意,默認(rèn)情況下 Groovy 編譯的類屬性是私有的,所以不能直接在 Java 中訪問它們,必須像下面這樣使用 setter:

@Testpublic void testToString(){ Song sng = new Song(); sng.setArtist("Village People"); sng.setName("Y.M.C.A"); sng.setGenre("Disco");		 Assert.assertEquals("Y.M.C.A, Village People, DISCO",    sng.toString());}

編寫這個(gè)測試用例余下的代碼就是小菜一碟了。測試用例很好地演示了這樣一點(diǎn):用 Groovy 所做的一切都可以輕易地在 Java 程序中重用,反之亦然。用 Java 語言執(zhí)行的一切操作和編寫的一切代碼,在 Groovy 中也都可以使用。

回頁首

結(jié)束語

如果說您從本教程獲得了一個(gè)收獲的話(除了初次體驗(yàn) Groovy 編程之外),那么這個(gè)收獲應(yīng)該是深入地認(rèn)識到 Groovy 就是 Java,只是缺少了您過去使用的許多語法規(guī)則。Groovy 是沒有類型、沒有修改符、沒有 return、沒有 Iterator、不需要導(dǎo)入集合的 Java。簡而言之,Groovy 就是丟掉了許多包袱的 Java,這些包袱可能會壓垮 Java 項(xiàng)目。

但是在幕后,Groovy 就是 Java。

我希望通向精通 Groovy 的這第一段旅程給您帶來了快樂。您學(xué)習(xí)了 Groovy 語法,創(chuàng)建了幾個(gè)能夠體驗(yàn)到 Groovy 的生產(chǎn)力增強(qiáng)功能的類,看到了用 Java 測試 Groovy 類有多容易。還遇到了第一次使用 Groovy 的開發(fā)者常見的一些問題,看到了如何在不引起太多麻煩的情況下解決它們。

盡管您可能覺得自己目前對 Groovy 還不是很熟練,但您已經(jīng)走出了第一步。您可以用目前學(xué)到的知識編寫自己的第一個(gè) Groovy 程序 — 畢竟,您已經(jīng)設(shè)置好了同時(shí)支持 Groovy 和 Java 編程的雙重環(huán)境!作為有趣的練習(xí),您可以試試用 Gant 設(shè)置下一個(gè)的自動構(gòu)建版本,Gant 是基于 Ant 的構(gòu)建工具,使用 Groovy 來定義構(gòu)建,而不是使用 XML。當(dāng)您對 Groovy 更加適應(yīng)時(shí),可以試著用 Groovy on Grails 構(gòu)建 Web 應(yīng)用程序模塊 — 順便說一下,這是下一篇教程的主題。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
利用 Eclipse 進(jìn)行單元測試
9. 類
gmock初體驗(yàn)
在編碼之前進(jìn)行測試(轉(zhuǎn)與Rational Edge)
php箭頭的用法是什么?
標(biāo)準(zhǔn)的Java編碼規(guī)范手冊
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服