1. 程式人生 > 其它 >Groovy系列(3)- Groovy基礎語法

Groovy系列(3)- Groovy基礎語法

Groovy基礎語法

動態型別

Groovy定義變數時:可以用Groovy風格的def宣告,不指定型別;也可以相容Java風格,指定變數型別;甚至還可以省略def或型別

def t1 = 't1'
String t2 = 't2'
t3 = 't3'

Groovy風格定義的變數型別是動態的,編譯成class時會自動轉換成正確的Java型別

def var = 'text'
println var
var = 5
println var + 1

可用Java實現類似效果如下

Object o = "text";
System.out.println(String.valueOf(o));
o 
= 5; System.out.println(String.valueOf(Integer.valueOf(o) + 1));

字串

Groovy支援靈活的字串語法,例如:

// 單引號字串
def a = 'hello "world"'

// 雙引號字串
def b = "What's the weather like?"

// 用加號連線字串,用等號對比字串
assert 'ab' == 'a' + 'b'

// 三個單引號字串,支援直接換行
def aMultilineString = '''line one
line two
line three'''

// 斜線字串中,反斜線不需要轉義,常用於正則表示式
def fooPattern = /.*foo.*/ // 雙引號字串支援用$嵌入變數 def name = 'Tom' def greeting = "Hello ${name}" // 如需函式呼叫,則$後表示式要加大括號 def pi = 3.14 def piString = "Pi = ${pi.toString()}"

閉包 (Closure)

  • 閉包是一個變數,又是一個函式,類似C語言中的函式指標,或者Java中只有一個方法的介面(Runnable等)
  • 反編譯class檔案可以看出,Groovy閉包都會轉化為繼承groovy.lang.Closure的類
  • 閉包方法的引數用箭頭定義,如果不特殊指定,則預設有一個it引數
  • 閉包方法的返回值可以用return顯示指定,如果不指定則使用最後一條語句的值
def c1 = {
    println 'hello'
}
def c2 = { a, b ->
    println a
    println b
}
def c3 = { int a, String b ->
    println a
    println b
}
def c4 = { ->
    println 'hello'
}
def c5 = {
    println it
}
def c6 = {
    return it + 1
}
def c7 = {
    it + 1
}

閉包呼叫可以用call,也可以直接像Java方法一樣加括號呼叫。

def c = {
    println it
}
c.call('text1')
c('text2')

Java實現閉包效果:

abstract class MyClosure {
    abstract void call(Object o);
}
MyClosure c = new MyClosure() {
    @Override
    void call(Object o) {
        System.out.println(String.valueOf(o));
    }
};
c.call("text");

方法/閉包的定義與呼叫

Groovy中定義方法既可以用Groovy閉包風格,也可以用Java風格,引數/返回值型別也是可選的

def f1 = { text ->
    println text
}
def f2(text) {
    println text
}
void f3(String text) {
    println text
}

注意函式定義不能這麼寫,會被視為函式呼叫

f4(text) {
    println text
}

呼叫帶引數的閉包/函式,通常可以省略括號,如果最後一個引數是閉包,還可以單獨寫在括號後面,如下:

println('hello')
println 'hello'

def func = { text, Closure closure ->
    println text
    closure.call()
}

func('1', {
    println '2'
})
func '3', {
    println '4'
}
func('5') {
    println '6'
}

delegate,owner,this

檢視Closure類的原始碼,可以發現閉包中有delegate、owner、this三個成員變數,呼叫閉包沒有的屬性/方法時,會嘗試在這三個變數上呼叫。一般情況下:

this指向閉包外部的Object,指定義閉包的類。
owner指向閉包外部的Object/Closure,指直接包含閉包的類或閉包。
delegate預設和owner一致,指用於處理閉包屬性/方法呼叫的第三方物件,可以修改。

在閉包構造時this和owner就已經確定並傳入,是隻讀的。如果需要修改,可以用Closure.rehydrate()方法克隆新的閉包,同時設定其this和owner。
Closure還有一個resolveStrategy屬性,有多種值(OWNER_FIRST、DELEGATE_FIRST、OWNER_ONLY、DELEGATE_ONLY、TO_SELF),預設為OWNER_FIRST,表示呼叫閉包沒有定義的屬性/方法時,先嚐試從owner取,再嘗試從delegate取。
Groovy程式碼示例:

class MyDelegate {
    def func = {
        println('hello')
    }
}
def c = {
    func()
}
c.delegate = new MyDelegate()
c.call()

用Java實現類似效果如下:

static boolean callMethod(Object o, String method, Object... args) {
    try {
        Method func = o.getClass().getDeclaredMethod(method);
        if (func != null) {
            func.invoke(o, args);
            return true;
        }
    } catch (Exception ignored) {
    }
    return false;
}
class MyDelegate {
    void func() {
        System.out.println("func");
    }
}
abstract class MyClosure {
    Object delegate;
    abstract void call();
}
MyClosure c = new MyClosure() {
    @Override
    void call() {
        if (!callMethod(this, "func")) {
            callMethod(delegate, "func");
        }
    }
};
c.delegate = new MyDelegate();
c.call();

屬性與Getter、Setter

Groovy中物件的屬性(通常即成員變數)可以直接用名字訪問,實際上會呼叫getter和setter
// File沒有absolutePath的成員變數,但有getAbsolutePath方法,可以直接當屬性訪問
println new File('text').absolutePath

// File沒有setAbsolutePath方法,這句會報ReadOnlyPropertyException
new File('text').absolutePath = '1'