http://www.sunnyang.com/522.html
上一篇文章Groovy入門之語法和變量定義重點記錄的是Groovy的語法以及變量,這一篇文章繼續學習Groovy的一些相關知識點。本文的重點是函數和閉包、類和對象,知識點涉及到與Java一樣的地方在文章中就不做介紹了,重點將一些與Java不同的地方。另外如果有人接觸過JavaScript,相信多數也了解JavaScript中閉包這個概念,但是Groovy中閉包與JavaScript閉包是兩個完全不同概念。
函數與閉包
函數
有些人可能對函數和方法的叫法一直不太清楚。事實上沒有本質區別,在面向過程的語言中一般稱為函數,在函數式編程中一般都叫做函數。方法的一般是類的方法,在某一個類中定義的稱之為方法。
1.在Groovy中除非指定了確定的返回類型,void也可以作為返回值的一種,否則定義函數必須加上關鍵字def。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
String getString(){
return "hello world"
}
def getDef(){
return "hello world"
}
void printSomething(){
println "hello worlld"
}
//錯誤的定義,編譯可以通過,但是運行時報錯
//getString(){
// return "hello world"
//}
|
2.在定義函數需要傳參時可以不設置設置參數的類型,默認是Object類型的,如果用def關鍵字設置參數類型,事實上也是使用的Object定義參數的。

|
1
2
3
4
5
6
7
8
9
10
11
|
def printSomething01(param){
println param
}
def printSomething02(int param){
println param
}
def printSomething03(def param){
println param
}
|
3.在調用函數時,如果所定義的函數有參數,在使用的時候可以不使用括號,但是必須得傳入參數,參數與函數名以空格隔開。
如果不出入參數必須添加括號,否則代碼編譯可以通過,但是運行時會出錯,會將函數誤認為是一個屬性。
如果所定義的函數沒有參數,在調用的時候必須添加括號,否則運行出錯,會將函數誤認為是一個屬性。
函數調用的時候參數的個數必須匹配,否則也會報錯,提示沒有定義該函數,如果單個參數除外,可以不用輸入參數,系統默認賦值null。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
def printSomething(param01,param02){
println param01+param02
}
printSomething ("hello","world")//helloworld
printSomething "hello","world"//helloworld
//參數個數不對,報錯
//printSomething ("hello")
def printOne(param){
println param
}
printOne()//null
|
4.函數可以有返回值,如果有顯示地使用return關鍵字,則返回return指定的返回值,其后面的語句不再執行。
如果沒有顯式地使用return關鍵字,則返回函數最后一行語句的運行結果。
如果使用void關鍵字代替def關鍵字定義函數,則函數的返回值將為null。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
def printSomething(){
return "hello"
println "world"
}
println printSomething()//hello
def printSomething01(){
"hello world"
1
}
println printSomething01()//1
def printSomething02(){
1
"hello world"
}
println printSomething02()//hello world
|
5.支持函數重載,當參數個數不同時,函數名稱可以同名。
|
1
2
3
4
5
6
7
8
9
10
|
def printSomething(param){
println param
}
def printSomething(param01,param02){
println param01+" "+param02
}
printSomething("hello")
printSomething("hello","world")
|
6.函數內不可以訪問函數外的變量
|
1
2
3
4
5
6
7
8
|
int m=1
def n="hello"
//error
def printSomething(){
println m//error
println n//error
}
printSomething()
|
7.Groovy支持不定長參數。
|
1
2
3
4
5
6
|
def printSomething(... params) {
println(params[0])
}
printSomething("hello")
printSomething("hello","world")
|
8.函數可以賦值給其它函數,使用語法標記&將函數賦予新的函數。
|
1
2
3
4
5
6
7
8
9
|
def printSomething() {
println("hello world")
}
//printSomething不可以加括號
def printHello=this.&printSomething
printHello()//hello world
printSomething()//hello world
|
閉包
在Javascript中閉包的定義:有權訪問另外一個函數作用域中的變量的函數。
Groovy中閉包是這么定義的:可以用作函數參數和方法參數的代碼塊。可以把這個代碼塊理解為一個函數指針。
閉包的定義格式:
|
1
2
3
|
def xxx = { params -> code }
//或者
def xxx={code}
|
在這里可以看出來這里的閉包跟JavaScript中以字面量形式定義對象格式類似。
|
1
2
|
var obj={username:"admin"}
console.log(obj.username);
|
從這里也可以看出來Groovy中閉包表示形式和閉包跟JavaScript中所講解的閉包是完全不同的。
1.閉包可以訪問外部的變量,記住一點方法是不能訪問外部變量的。
|
1
2
3
4
5
6
7
|
def str="hello world"
def closure={
println str
}
closure()//hello world
|
2.閉包調用的方式有兩種,閉包.call(參數)或者閉包(參數),在調用的時候可以省略圓括號。
|
1
2
3
4
5
6
7
|
def closure = {
param -> println param
}
closure("hello world")
closure.call("hell call")
closure "hello world"
|
3.閉包是有返回值的,默認最后一行語句就是該閉包的返回值,如果最后一行語句沒有不輸入任何類型,閉包將返回null。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
def closure = {
println "hello world"
return "I'm callback"
}
//hello world
//I'm callback
println closure()
def noReturn={
println "hello world"
}
//hello world
//null
println noReturn()
|
4.閉包可以有參數,如果沒有定義參數,會有一個隱式的默認參數it,如果沒有參數可以將[參數]和[->]省略。
如果存在參數,在[->]之前的就是參數,如果只有一個參數,參數可以省略。
閉包中參數名稱不能與閉包內或閉包外的參數名重名
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
def closure={
println "hello $it"
}
closure("admin")
def closure={
param01,param02,param03->println param01+param02+param03
}
closure "hello","world","ok"
def closure={
println it
}
closure "hello world"
//編譯時就不通過
//def param
//def closure={
// param->println param
//}
|
5.閉包可以作為一個參數傳遞給另一個閉包,也可以在閉包中返回一個閉包。
|
1
2
3
4
5
6
|
def toTriple = { n -> n * 3 }
def runTwice = { a, c -> c(c(a)) }
println runTwice(5, toTriple)//45
def times = { x -> { y -> x * y } }
println times(3)(4)//12
|
6.閉包的一些快捷寫法,當閉包作為閉包或方法的最后一個參數,可以將閉包從參數圓括號中提取出來接在最后。
如果閉包中不包含閉包,則閉包或方法參數所在的圓括號也可以省略。
對於有多個閉包參數的,只要是在參數聲明最后的,均可以按上述方式省略。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
def runTwice = { a, c -> c(c(a)) }
println runTwice(5, { it * 3 }) //45 usual syntax
println runTwice(5) { it * 3 } //45
def closure = {
param -> println param
}
closure "hello world"
def runTwoClosures = { a, c1, c2 -> c1(c2(a)) }
//when more than one closure as last params
assert runTwoClosures(5, { it * 3 }, { it * 4 }) == 60 //usual syntax
assert runTwoClosures(5) { it * 3 } { it * 4 } == 60 //shortcut form
|
7.閉包接受參數的規則,會將參數列表中所有有鍵值關系的參數,作為一個map組裝,傳入閉包作為調用閉包的第一個參數。
|
1
2
|
def f= {m, i, j-> i + j + m.x + m.y }
println f(6, x:4, y:3, 7)//20
|
8.如果閉包的參數聲明中沒有list,那么傳入參數可以設置為list,里面的參數將分別傳入閉包參數。
|
1
2
3
|
def c = { a, b, c -> a + b + c }
def list = [1, 2, 3]
println c(list) // 6
|
類和對象
Groovy類與Java類似,在字節碼級都被編譯成Java類,由於其在定義變量上面的靈活性,所以在新建一個Groovy類時還是有一些不同的,增加了許多靈活性。由於Groovy是松散型語言,它並不強制你給屬性、方法參數和返回值定義類型。如果沒有指定類型,在字節碼級別會被編譯成Object。在定義類的屬性時不用刻意加上權限修飾符,默認就是public的。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
class Book{
def title
String author
private int price
public Book(title){
this.title=title
}
boolean order(int isbn){
true
}
def title(){
"Booke Title"
}
}
Book book=new Book("Hello Groovy")
book.order(1001)
book.title//獲取屬性
book.title()//訪問方法
|
如果我們將Book類看做是一個JavaBean,事實上Groovy在編譯完成后會自動幫助我們生成getter與setter方法,但是私有屬性除外也就是說price屬性我們不能使用getter與setter方法。
|
1
2
3
4
5
6
7
|
Book book=new Book("Hello Groovy")
println book.getTitle()//Hello Groovy
book.setTitle("New Groovy")
println book.getTitle()//New Groovy
println book.title////New Groovy
|
在Groovy中類名和文件名並不需要嚴格的映射關系,我們知道在Java中主類名必須與文件同名,但是在Groovy中一個文件可以定義多個public類。
在Groovy中可以定義與任何類不相關的方法和語句,這些方法通常稱為獨立方法或者松方法。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class Hello{
public static String hello(){
return "hello"
}
}
class World{
public static String world(){
return "world"
}
}
println Hello.hello()+World.world()
def helloWorld(){
return "hello world"
}
|
上面一個文件名定義為Structure.groovy,在這個文件中包含了類的定義和獨立方法聲明,它編譯之后會發生什么呢。首先會生成一個與文件同名的class文件。所有的松語句都集中在run方法中,並且run方法被該類的main方法調用。獨立方法被編譯成了類的靜態方法。與Java相似,每一個獨立的類都會被編譯成一個單獨的class文件。因此編譯Structure.groovy文件最后會被編譯成Hello.class、World.class和Structure.class。上面一個文件名定義為Structure.groovy,在這個文件中包含了類的定義和獨立方法聲明,它編譯之后會發生什么呢。首先會生成一個與文件同名的class文件。所有的松語句都集中在run方法中,並且run方法被該類的main方法調用。獨立方法被編譯成了類的靜態方法。與Java相似,每一個獨立的類都會被編譯成一個單獨的class文件。因此編譯Structure.groovy文件最后會被編譯成Hello.class、World.class和Structure.class。
本文地址:www.sunnyang.com/522.html
小結
有關Groovy的學習就先到這里,有關Groovy基礎語法的講解可以參看Groovy入門之語法和變量定義這篇博文,兩篇文章主要還是偏重中一些基本使用,為的是可以更好的理解應用Android Studio的Gradle工具。筆記的記錄基本都是通過瀏覽別人博客以及《Java腳本編程:語言、框架與模式》這本書,由於個人能力所限,文章中難免有錯誤疏漏之處,如若發現還望及時指出以求共同進步。
