本文主要介紹閉包,方法引用相關知識。 閉包是{ [closureParameters -> ] statements }這種形式的代碼塊,可以接收參數,返回值,并且可以復制給某個變量,閉包里面可以引用外部的變量。具體可參考http://docs.groovy-lang.org/next/html/documentation/#_closures ,里面說的很詳細。 閉包肯定會返回值,不像方法可能無返回值。
每個閉包都有這3個概念,this、owner和delegate,這3個概念很像,容易搞糊涂。
this:定義閉包的class對象owner:定義閉包的class對象或者閉包對象delegate:一個第三方對象,如果閉包內找不到方法或者屬性就去delegate里面找。一個閉包的this指向的必然是一個class對象,而不是閉包對象,如下所示,
Enclosing內的閉包whatIsThis的this指向Enclosing對象。 而EnclosedInInnerClass里面,閉包cl定義在Inner里面,所以cl的this指針是Inner對象而不是EnclosedInInnerClass對象。NestedClosures里面的閉包cl是定義在另一個閉包nestedClosures里面的,所以cl的this是NestedClosures對象,而不是nestedClosures閉包class Enclosing { void run() { def whatIsThisObject = { getThisObject() } assert whatIsThisObject() == this def whatIsThis = { this } assert whatIsThis() == this }}class EnclosedInInnerClass { class Inner { Closure cl = { this } } void run() { def inner = new Inner() assert inner.cl() == inner }}class NestedClosures { void run() { def nestedClosures = { def cl = { this } cl() } assert nestedClosures() == this }}owner跟this基本一樣,唯一不同就是owner可以是閉包。所以下邊代碼里的cl的owner就是nestedClosures。
class NestedClosures { void run() { def nestedClosures = { def cl = { owner } cl() } assert nestedClosures() == nestedClosures }}delegate是groovy里比較難理解的概念,簡單的說如果一個閉包在執行的時候發現某個參數未定義,那么就會去他的owner以及delegate里面找(默認是先owner后delegate)。其實這么說起來delegate就是相當于java里的非靜態內部類持有外部類的引用,delegate就是外部類的引用。默認情況下delegate就是owner。delegate在DSL里面是非常有用的。
如下所示,say這個閉包需要m變量,但是m未定義,如果直接執行say()肯定不行,在這里我們給say.delegate=eee,而eee這個map里邊是有m這個變量的,所以在L9執行的時候,發現閉包內m未定義,就去他的delegate eee里找,找到了m,所以最后結果就是打印出2
def say = { PRintln m}//say.delegate = [m:2]eee=[m:2]assert eee.m==2say.delegate=eeesay()在這里,我們定義了一個閉包upperCasedName,通過指定delegate,改變閉包的執行主體,這看起來和傳函數參數類似。閉包的delegate是可以不寫的,因為閉包找不到成員的時候就會調用delegate的方法,所以閉包可以這么寫
def upperCasedName = { name.toUpperCase() }我們知道在字符串插值的時候,可以用${}占位,里面放任意表達式。實際上還可以用${->}占位里面放閉包表達式。此時有一個特性,惰性求值(lazy evaluation).如下所示,對于普通的插值表達式eagerGString,被賦值為1之后,將不再改變。而對于閉包插值lazyGString來說,他每次GString轉換為String的時候都會調用閉包,生成一個新的字符串
如果一個函數與一個閉包擁有相同的名稱和參數,則調用的時候將執行函數,而不是閉包
.&groovy支持方法引用,如下所示,upper就是一個方法引用,方法引用操作符的左邊是個對象(還可以是this),右邊是方法名。
注意下邊fun是一個閉包,fun()是字符串‘EXAMPLE OF METHOD REFERENCE’
def str = 'example of method reference'def str2="s"def fun = str.&toUpperCasedef upper = fun()assert upper == str.toUpperCase()assert upper != str2.toUpperCase()println(upper)println(fun)println(fun())assert fun instanceof Closureassert fun() instanceof String方法無參數的時候,閉包就相當于一個簡單的函數指針。
def f(){ println "Hello,world!";}def s=this.&f;s();這個就更吊了,只要有方法名,可以訪問不同類型的對象,如下所示,reference是個閉包,往里面傳個’foo’就會調用doSomething(String str)方法,往里頭傳個123,就會調用doSomething(Integer x)方法,這個簡直是多態的升級版。
def doSomething(String str) { str.toUpperCase() } def doSomething(Integer x) { 2*x } def reference = this.&doSomething assert reference('foo') == 'FOO' assert reference(123) == 246如下所示filter是個閉包,他有且只有一個參數,這個參數就可以隱藏,用到的時候用it來指代(用法有點像this)
def filter = { it.contains 'G' }assert filter("Groovy")==trueA SAM type is a type which defines a single abstract method. This includes:
interface Predicate<T> { boolean accept(T obj)}http://docs.groovy-lang.org/next/html/documentation/#_closures groovy 官方sdk http://groovy.zeroleaf.com/ http://wiki.jikexueyuan.com/project/deep-android-gradle/four-two.html http://dublintech.blogspot.hk/2014/05/groovy-closures-this-owner-delegate.html
新聞熱點
疑難解答