1. 程式人生 > >教妹學 Java:動態伴侶 Groovy

教妹學 Java:動態伴侶 Groovy

 

00、故事的起源

“二哥,聽說上一篇《多執行緒》被 CSDN 創始人蔣濤點讚了?”三妹對她提議的《教妹學 Java》專欄一直很關心。

“嗯,有點激動。剛開始還以為是個馬甲,沒想到是真人!”

“其實蔣濤點讚的文章很多很多了,二哥的只是其中一篇而已。”三妹出乎意料地潑起了冷水。

“你說得沒錯。但這的確給我注入了新的能量,蔣濤畢竟是業界的大佬啊。”

“那就讓我們開始新的篇章吧!我繼續來提問,二哥你繼續回答。”三妹已經迫不及待了。

01、二哥,什麼是 Groovy 啊?

三妹啊,聽哥來給你慢慢講啊。

Groovy 是一種面向物件的動態型別語言,跟 Java 一樣,可以執行在 JVM 上。

之所以稱 Groovy 為“動態”型別語言,是因為 Groovy 的語法源於 Smalltalk 和 Ruby,提供了比 Java 更簡單、更靈活的語法,可以在執行時動態地進行型別檢查。

Java 語言是一種固定型別語言,比如說整形變數 int a = 0;,字串變數 String s = "Wanger"。但在 Groovy 中,不必指定變數的型別(可選的),變數的型別是在宣告(或返回)的時候確定的。

比如說可以把一個整形賦值給變數 a,然後緊接著把一個字串賦值給變數 a。

a = 0;
a = "Wanger";

a 雖然沒有指定型別,但 a 在被賦值為 0 的時候為整形,被賦值為 “Wanger” 的時候為字串型別。

Groovy 程式碼能夠完美地相容 Java 程式碼,可以用來作為 Java 的一種補充。你甚至可以用 Groovy 在 Java 平臺上進行 Java 程式設計,使用方式基本上和使用 Java 程式碼的方式相同。

許多 Java 開發人員非常喜歡 Groovy 程式碼和 Java 程式碼的相似性。因為從學習的角度看,如果知道如何編寫 Java 程式碼,那麼也就知道如何編寫 Groovy 程式碼。

Groovy 之所以能夠獲得 Java 開發者的青睞,最主要原因在於完成同樣的任務所需的 Groovy 程式碼比 Java 程式碼更少,因為 Groovy 具有鬆散的語法(允許省略分號)和一些特殊功能(比如說 JavaScript 中經常提到的閉包)。

02、二哥,能否 Hello World 一下?

三妹,Hello World 是必須的。就像你去買包包,總要先試試,再貨比三家,對吧?

還記得用 Java 編寫的 Hello World 嗎?

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

然後我們編譯它:

javac Wanger.java

再然後我們執行已經編譯好的類:

java Wanger

不出意外的話,你會在螢幕上看到“Hello World”。

那如果用 Groovy 來編寫 Hello World 呢?

println "Hello World"

嗨,有沒有被驚訝到了呢?

1)Groovy 鬆散的語法讓我們不需要為列印 “Hello World” 這樣的簡單操作定義類。

2)Groovy 會非常聰明地為我們在 println 前面加上 System.out。

3)main 方法也不需要了。

假設程式碼儲存在 Wanger.groovy 檔案中,可以跳過編譯階段直接執行:

groovy Wanger.groovy

為什麼連編譯也不需要呢?因為 Groovy 屬於指令碼語言,可以在執行時進行解釋。當然了,你也可以按照編譯再執行的步驟來:

groovyc Wanger.groovy
groovy Wanger

用 groovyc 編譯的 Groovy 程式碼會產生標準的 Java 位元組碼,然後也可以通過 java 命令執行生成的位元組碼。

注意,在命令列中執行 Groovy 程式碼的前提是,你需要先到 Groovy 的官網下載免安裝包,再將其解壓後配置到環境變數中,就像當初你配置 Java 環境變數那樣。

下載地址如下:

https://groovy.apache.org/download.html

03、二哥,怎麼安裝 Groovy 啊?

三妹啊,由於哥一直使用 Eclipse 作為整合開發環境,所以這次的安裝就以 Eclipse 的 Groovy 外掛為例。

第一步,開啟 Eclipse,在 Help 選單中選擇 Eclipse Marketplace,搜尋 groovy 關鍵字,結果如下圖所示。

第二步,點選 install 按鈕,在功能選擇對話方塊中勾選全部,然後點選 Confirm 按鈕。

第三步,在許可證確認對話方塊中勾選 I accept the terms of the license agreement,點選 Finish 按鈕。

第四步,安裝成功後,重啟 Eclipse。這時候,就可以建立一個 Groovy 的專案了,如下圖所示。

第五步,建立一個 Groovy 的測試類,勾選 static void main(args) 選項,如下圖所示。

生成的程式碼如下:

package groovyTest

class Wanger {

    static void main(args) {

    }
}

這和之前 Java 版的 HelloWorld 驚人地相似,但沒有 public 修飾符,並且 main 方法的引數沒有型別。

這時候,我們在 main 方法內加入 println "Hello World"

package groovyTest

class Wanger {

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

我們可以直接選擇 Run As Java Application 來執行 Groovy 程式碼,因為 Groovy 實際上就是 Java,只不過語法有所不同,多數情況下會短一些,但 Groovy 程式碼 100% 符合 Java 位元組碼的標準。

04、二哥,Groovy 有哪些 Java 不具備的特性呢?

三妹啊,你這個問題就問得很到位啊。

大多數情況下,Java 開發者更希望利用 Groovy 的特性來替代一些 Java 中不夠優雅的解決方案。

像 Groovy 中一些可以省略的語法,比如說:

  • 語句結束處的分號;
  • 返回語句的 return 關鍵字;
  • 方法引數兩邊的括號;
  • public 訪問限定符;
  • ……

這些並不是 Java 開發者要學習 Groovy 這門新語言的動力,那是什麼呢?

1)Groovy List

在 Java 中,List 的操作方法大致如下:

List<String> list = new ArrayList<>();
list.add("沉默");
list.add("王二");

for (String s : list) {
    System.out.println(s);
}

但在 Groovy 中,操作方法變得更加便捷了。

可以像定義陣列一樣定義 list,就像下面這樣:

def list = ["沉默", "王二"];

向 list 中新增元素也變得多種多樣:

list.add("勇士");
list << "猛龍";
list[4] = "火箭";

也可以像陣列一樣取出元素:

def wanger = list[1];

2)Groovy Map

在 Java 中,Map 的操作方法大致如下:

Map<String, String> map = new HashMap<>();
map.put("name", "沉默王二");

但在 Groovy 中,操作方法變得更加便捷了。

可以按照以下方法定義一個 Map:

def map = [name:"沉默王二", "age":18];

注意:Groovy 中的鍵不必是字串(可以不帶雙引號)。

向 map 中新增元素也變得多種多樣:

map.put("money", 10000000);
map.sex = "保密";
map["work"] = "自由職業";

取出元素可以使用 . 或者 []

map.money;
map["work"]

3)Groovy 閉包

JavaScript 開發者一定不會對下面這句話感到陌生:

當一個函式被建立並傳遞或從另一個函式返回時,它會攜帶一個揹包,揹包中是函式宣告時作用域內的所有變數。

這句話裡面的“揹包”就對閉包的一個恰當的比喻。Groovy 的官網是這樣描述閉包的:

A closure in Groovy is an open, anonymous, block of code that can take arguments, return a value and be assigned to a variable.

大致的意思就是說,Groovy 閉包是一個開放的、匿名的程式碼塊,可以接受引數,並把返回值賦值給變數。

閉包的定義方式如下:

{ [closureParameters -> ] statements }

其中 [closureParameters] 是以逗號分隔的引數列表,statements 是 0 個或者多個 Groovy 語句。 -> 操作符用於將引數列表與 Groovy 語句隔開。

我們來用閉包遍歷一下列表,方式如下:

list.each({ x -> println x});

其中 { x -> println x} 就是一個閉包,把它作為 each() 方法的引數就可以將 list 中的元素取出,並且打印出來。

另外,閉包還有一個預設引數 it,它不需要像 x 一樣宣告出來,於是遍歷 list 的程式碼就變成了下面這樣:

list.each({println it});

接下來,我們再來看一下遍歷 map 的方法,就是像變魔法一樣。

可以使用預設的 it 作為元素,it.key 為鍵,it.value 為值。

map.each { println it.key + it.value }

注意: each() 方法的 () 還可以省略。

還可以自定義變數 item 作為元素,item.key 為鍵,item.value 為值。

map.each { entry -> println entry.key + entry.value }

或者,直接使用 key 和 value。

map.each { key, val -> println  key + val }

我們來自定義一個閉包,就像下面這樣:

def addX = { x ->
    return x + 1;
};

addX 是這個閉包的名字,它接受一個引數 x,返回 x + 1。然後,我們可以這樣來呼叫閉包:

println addX(3);
println addX.call(addX(3));

閉包在 Groovy 中不僅是一個方法,也是一個物件,所以它既可以作為引數傳遞,也可以呼叫方法。

05、故事的未完待續

“二哥,Groovy 有這麼多引人注目的特性,使得它成為了一門出色的可以和 Java 共用的語言。但用 Groovy 的人並不多呢?”三妹所有所思的問。

“三妹啊,這是一個好問題呢,不過答案也顯而易見。下圖來自於 Groovy 官網,可以看到很多大廠的名字:Google、IBM、Linkedin、SONY。”

“不過,我聽說 Java 8 中出現的 Lambda 表示式也能寫出和 Groovy 一樣簡潔靈活的程式碼,你能不能教教我呢?”三妹的眼睛裡充滿了期待。

“三妹,你竟然知道 Lambda表示式……”

&n