基本類型
其實在 Groovy 中是沒有基本類型的,例如下所示:
int x = 10;
println(x.class)
打印結果如下:
class java.lang.Integer
可以看到他是一個 Integer 對象。其實在底層編譯的時候已經將 int 裝箱成了 對象。
變量的定義
groovy 定義變量有兩種方式,分別是 強類型定義 和 若類型定義,強類型定義和 java 中的意義,但是弱類型定義是什麼呢,如下:
//強類型定義方式
int x = 10;
println(x.class)
//弱類型定義方式
def x1 = 1;
println(x1.class)
def x2 = 3.14;
println(x2.class)
def x3 = "Android"
println(x3.class)
結果如下:
class java.lang.Integer
class java.lang.Integer
class java.math.BigDecimal
class java.lang.String
第二行 是大數據類型
其實弱類型定義就是不指定具體的類型。通過值來確定它到底是什麼類型。用 def 來定義
如何選擇呢?如果在本類中使用,則建議使用 def 類型。但是別的類也要用到這個變量。則儘量使用強類型定義;def 聲明的變量類型可以隨時改變,如 x1 是 Integer 。如果給 x1 賦值爲 String,這樣他就會變爲 String。正是這個原因所以纔不建議在 別的類使用這個變量時定義爲 def。
字符串
常用的定義方式:
//1,通過 單引號定義String ,和雙引號沒有任何區別 ,轉義 '單引號 \'String \''
def name = '單引號 String'
println(name)
//2,通過三個單引號定義String ,但定義的格式進行輸出,
def name1 = '''第一行
第二行
第三行'''
println(name1)
// 3,雙引號 ,可擴展字符串,擴展後使用的不是String,而是GString類
def name2 = "雙引號"
def hello = "hello ${name2}"
println(name2)
println(hello.class)
//可擴展字符串使用 ,可以擴展任意的表達式
def sum = "sum = ${5 - 6 - 6 + 12}"
println(sum)
def result = echo(sum)
println(result)
String echo(String message){
return message;
}
通過上面這幾種方式可以 定義字符串,其實一般最常用的就是 第三種了。注意擴展後的字符串就不是 String。而是 GString。不信的話可以打印看一下。
字符串方法
字符串的方法
1,第一種就是String類原有的方法
2,第二種則是 DefaultGroovyMethods ,是 Groovy 對所有對象的擴展
3,第三種是 StringGroovyMethods ,繼承自 DefaultGroovyMethods 。
重點要看的是 StringGroovyMethods 。他繼承自第二種,第一種是 String,比較熟悉。
首先定義一個字符串:
String str = "哈哈哈"
-
填充
println str.center(8, 'a') //填充: aa哈哈哈aaa println str.padLeft(8, 'a') //填充:aaaaa哈哈哈
-
比較
println str > "嘻嘻嘻" //通過運算符比較字符串大小 :false
-
索引
println str.getAt(0) //下標爲0 :哈 println str[0] //通過類似於數組的方式來獲取 :哈 println str[0..1] //指定範圍 :哈哈
-
減法
println str.minus("哈哈") //減法 : 哈 --減去兩個剩一個 。 println str - "哈哈";
-
倒序
println str.reverse()
-
首字母大寫
println str.capitalize()
-
判斷 str 是否爲數字類型
println str.isNumber()
-
轉爲基本數據類型
println str.toInteger() println str.toBoolean() println str.toDouble()
-
其實方法還有很多,這裏就不一一列舉了。
控制語句
switch:groovy 中的 switch 和 java 中的有明顯的不同,它可以接受任意的數據類型。如下:
// switch ,可以傳入任意類型的數據
def x = 1.23
def result;
switch (x) {
case '哈哈哈哈':
result = '0'
break
case '嘻嘻':
result = '1'
break
case [4, 5, 6, 'inlist']: //列表
result = '2'
break
case 12..30: //範圍
result = '3'
break
case Integer:
result = '4'
break
case BigDecimal:
result = '5'
break
default:
result = 'defalut'
break
}
println result //5
for 循環
// 對範圍的 for 循環
def sum = 0
for (i in 0..9) {
sum += i
}
println sum
//對 list 進行循環
sum = 0
for (i in [1, 2, 3, 4, 5, 6, 7, 8, 7]) {
sum += i
}
println sum
//對 map 進行循環
sum = 0;
for (i in ['one': 1, 'two': 2, "three": 3]) {
sum += i.value
}
println sum;
// 45
// 43
// 6
閉包
基礎詳解
閉包是一個開放的,匿名的代碼塊,可以帶參數,返回一個值。可以通過一個變量引用到他,也可以傳遞給別人進行處理。
-
閉包的創建和調用
def clouser = { println "hello groovy" } //兩種方式調用閉包 clouser.call() // hello groovy clouser() // hello groovy
-
創建帶參數的閉包和調用
def clouser = { //箭頭前面是參數,後面是閉包體 String name, int age -> println "hello groovy ${name} -- ${age}" } //調用帶參數閉包 clouser.call("張三", 32) // hello groovy 張三 -- 32 clouser("李四", 23) //hello groovy 李四 -- 23
-
默認參數
//每一個閉包都有一個默認的 it 參數,如果不想使用,則顯示的定義即可。 def clo = { println "hello ${it}" } clo.call("李四") //hello 李四
-
閉包返回值
def clouser = { //箭頭前面是參數,後面是閉包體 String name, int age -> return "hello groovy ${name} -- ${age}" } //調用帶參數閉包 println clouser.call("張三", 32) //hello groovy 張三 -- 32
使用詳解
基本類型結合使用:
-
階乘
int x = 5 println fab(x) //求 number 的階乘 int fab(int number) { int reslut = 1 //調用 upto 方法,傳入 number 和 閉包 ,閉包中有一個 num 參數 1.upto(number, { num -> reslut *= num }) return reslut } //結果:120
爲什麼要這樣寫呢?看一下源碼秒懂!
//打眼一看這裏需要三個參數,我們只傳了兩個?,注意:1.upto()中的 1,代表的是第一個參數, public static void upto(Number self, Number to, @ClosureParams(FirstParam.class) Closure closure) { //拿到開始的位置和結束的位置 int self1 = self.intValue(); int to1 = to.intValue(); //小於等於 if (self1 <= to1) { for (int i = self1; i <= to1; i++) { //調用傳入的閉包,將i 傳進去,從這裏就可以知道我們寫的閉包爲啥要一個 num 的參數了。 closure.call(i); } } else throw new GroovyRuntimeException("The argument (" + to + ") to upto() cannot be less than the value (" + self + ") it's called on."); }
-
階乘2
int fab2(int number) { int result = 1 number.downto(1) { num -> result *= num } return result } //結果:120
你知道 downto 方法傳入了幾個參數嗎。。。。沒錯,是3個,number是一個,1 是一個,括號外面的閉包是一個。閉包寫在括號外面和寫在裏面效果完全一樣。這個是倒着來的。具體的可以查看源碼。
-
累加
int cal(int number) { int result // times 只有兩個參數,所以可以使用這種方式來寫 ,具體的實現可以看源碼,非常簡單 number.times { num -> result += num } return result; }
字符串的結合使用
定義一個字符串:
String str = "the 2 and 3 is 5"
-
each 遍歷
str.each { String temp -> print temp //the 2 and 3 is 5 } //看一下 each 方法的源碼 public static <T> T each(T self, Closure closure) { //第一個是迭代器,第二個則是閉包了 each(InvokerHelper.asIterator(self), closure); return self; } public static <T> Iterator<T> each(Iterator<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) { //遍歷 字符串, while (self.hasNext()) { Object arg = self.next(); //調用閉包,傳入了一個參數,從這裏就可以知道我們在定義閉包的時候需要加一個參數 closure.call(arg); } return self; }
-
查找符合條件的第一個
println str.find { String s -> //返回 boolean 。是否符合條件,這裏的條件爲:是否是數字 s.isNumber() } //結果:2 ,第一個符合結果的是2,看一下源碼 public static Object find(Object self, Closure closure) { //將閉包弄成了 boolean 類型的 BooleanClosureWrapper bcw = new BooleanClosureWrapper(closure); //迭代 for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) { Object value = iter.next(); //調用閉包,如果返回 true。則表示滿足條件,接着就將 value 返回,然後就退出了。不在執行 if (bcw.call(value)) { return value; } } return null; } //查找全部 println str.findAll { String s -> return s.isNumber() } //結果:[2, 3, 5] ,查看源碼可知找到後會存在集合中,最後進行返回
-
判斷是否包含數字
println str.any { String s -> return s.isNumber() // true } //源碼可自行查看
-
字符串是否每一項都爲數字
println str.every { String s -> s.isNumber() //false } //源碼 public static boolean every(Object self, Closure predicate) { return every(InvokerHelper.asIterator(self), predicate); } public static <T> boolean every(Iterator<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure predicate) { BooleanClosureWrapper bcw = new BooleanClosureWrapper(predicate); while (self.hasNext()) { //是否滿足閉包中的條件 if (!bcw.call(self.next())) { return false; } } //循環完成後表示都滿足條件,返回true return true; }
-
將字符串轉爲集合
println str.collect { //將 字符轉換大寫 it.toUpperCase() } //查看源碼 public static <T> List<T> collect(Object self, Closure<T> transform) { //這裏創建了一個新的集合 return (List<T>) collect(self, new ArrayList<T>(), transform); } public static <T> Collection<T> collect(Object self, Collection<T> collector, Closure<? extends T> transform) { //給字符串加上迭代器 return collect(InvokerHelper.asIterator(self), collector, transform); } public static <S,T> Collection<T> collect(Iterator<S> self, Collection<T> collector, @ClosureParams(FirstParam.FirstGenericType.class) Closure<? extends T> transform) { while (self.hasNext()) { //調用閉包中的方法,將返回的結果保存到集合中 collector.add(transform.call(self.next())); } //返回集合 return collector; }
進階詳解
-
閉包關鍵變量 this,owner,delegate
this:閉包定義處的類
owner :代表閉包定義處的類或者對象。因爲閉包是可以嵌套的,當閉包嵌套的時候,owner 就是閉包,而不是所處的類
delegate:任意一個對象,默認與 owner 一樣
看一個例子:
def clouser = { println this //閉包定義處的類 println owner //代表閉包定義處的類或者對象,因爲閉包是可以嵌套的,如果 閉包中有嵌套,則 owner 代表的就是閉包 println delegate //任意一個對象。默認與 owner 一致 } clouser.call() //結果: variable.ClooseStudy@5acf93bb variable.ClooseStudy@5acf93bb variable.ClooseStudy@5acf93bb
可以看到這三個結果是一樣的。因爲這裏的閉包沒有嵌套,所以 owner 是定義閉包處的類,delegate 則和 owner 一致
接着看:
//定義了一個內部類 class PerSon { //靜態閉包 def static classClouser = { println "Class " + this println "Class " + owner println "Class " + delegate } //靜態方法 def static say() { def classClouser = { println "method " + this println "method " + owner println "method " + delegate } classClouser.call() } } //結果: Class class variable.PerSon Class class variable.PerSon Class class variable.PerSon method class variable.PerSon method class variable.PerSon method class variable.PerSon
其實這個和上面的都差不多,這裏的 this 就是內部類了,而 owner 因爲不是嵌套,所以也是 Person。delegate 就不用說了。注意:這裏的結果後面沒有內存地址是因爲 閉包和方法都是靜態的。
接着看:
//閉包中定義一個閉包 def nestClouser = { def innerClouser = { println "innerClouser " + this println "innerClouser " + owner println "innerClouser " + delegate } innerClouser.call() } nestClouser.call() //結果: innerClouser variable.ClooseStudy@6cd28fa7 innerClouser variable.ClooseStudy$_run_closure2@f0c8a99 innerClouser variable.ClooseStudy$_run_closure2@f0c8a99
這裏的 this 是當前類,但是 owner 不一樣了,可以看到他在後面拼接了一點地址,這個就是外層閉包的對象。delegate 默認和 owner 一樣,所以他們兩個一樣。你可以打印一下 nestClouser 的地址看一下是否和 owner 一樣。。
如果修改了 delegate 的值,則他和 owner 就不一樣了。注意:this 和 owner 是不能被修改的,只有 delegate 可以修改
閉包委託策略
首先看一段代碼
class Student {
String name
def pretty = {
"My name is ${name}"
}
String toString() {
pretty.call()
}
}
class Teacher {
String name
}
def student = new Student(name: '張三')
def teacher = new Teacher(name: "老師")
println student.toString()
定義了兩個類,一個學生和一個老師。
如果調用 student 的 toString 方法,會打印什麼信息呢?
My name is 張三
可以看到打印的是張三。那如果要打印 Teacher 的 name 呢?這個時候就要用到 委託策略了
student.pretty.delegate = teacher
println student.toString()
將 teacher 傳給 student 的閉包的 delegate 。這個時候在輸出一下,你會發現沒有任何改變。。。
我們少改了一個東西, 默認的委託策略是 OWNER_FIRST ,即從 owner 中開始尋找對象 。owner 指向的是當前類 student。所以纔沒有發生任何變化。所以我們要修改委託策略:
student.pretty.delegate = teacher
student.pretty.resolveStrategy = Closure.DELEGATE_FIRST //修改委託策略
println student.toString()
//My name is 老師
修改爲 DELEGATE_FIRST 後會從 delegate 中開始尋找,因爲上面指定了 delegate 是 teacher ,所以輸出就變了
修改 Teacher 中的 name 字段名字,如下:
class Teacher {
String name1
}
def teacher = new Teacher(name1: "老師")
這個時候在運行會發現 運行的結果是 張三 ,因爲 student 中的閉包裏面用的是 name,而不是 name1,所以找不到 name 後就會尋找當前類的 name。
修改一下委託策略,如下:
student.pretty.resolveStrategy = Closure.DELEGATE_ONLY
接着在運行一下會報錯:
name for class: variable.Teacher Possible solutions: name1
在 Teacher 中 沒有找到 name ,所以報錯。這個策略只會從 delegate 中尋找,而不會從當前類中找
委託策略一共有四種:
public static final int OWNER_FIRST = 0;
public static final int DELEGATE_FIRST = 1;
public static final int OWNER_ONLY = 2;
public static final int DELEGATE_ONLY = 3;
默認的就是 OWNER_FIRST ,即從 owner 中開始尋找。
列表
//列表
def list = [1, 23, 324, -5, 6] // groovy 中定義的方式,和上面的完全一樣 ,並且添加元素。
println list.class
//排序
list.sort()
println list
list.sort {
a, b ->
a > b ? 0 : -1
}
println list
//按字符串長度排序
def strList = ['a', 'ab', 'abc', 'aaaaa', 'b', 'cadfa', 'ace']
strList.sort {
it ->
return it.size()
}
println strList
//查找被 2 整除
println list.findAll() {
return it % 2 == 0
}
// 判斷是否列表中元素是否都能夠被 2 整除
println list.every {
return it % 2 == 0;
}
println list.min() //最小值
println list.max() //最大值
println list.min { Math.abs(it) } //絕對值 最小值
println list.max { Math.abs(it) } //絕對值 最小值
println list.count {
return it % 2 //統計,有多少偶數
}
//添加
list.add(5)
list.leftShift(4)
println list + [4, 5]
//刪除
list.remove(0) //刪除下標爲 0 的元素
println list
list.remove((Object) 4) //刪除內容爲 4 的元素
println list
println list.removeAt(0) //刪除指定位置元素,並返回此元素
list.removeElement(0) //刪除
println list - [1, 23] //刪除 1 和 23
上面是列表的定義和常用的方法
有沒有感覺和數組的定義一樣。當然數組的定義方式也變了,如下:
//數組
def array = [1, 3, 4, 5] as int[]
// groovy 中 數組的定義
int[] array2 = [13, 4, 5, 6] //強類型數組定義
Map
//定義
def map = [red: '紅色', yellow: '黃色', black: '黑色']
//查找
println map.get('red')
println map['yellow']
println map.black
println map.find {
it.getValue().equals("紅色")
}
//計數
println map.count {
it.value.equals('黃色')
}
println map.findAll {
return it.key.equals('red') //key 爲 red
}.collect {
it.value //key 爲 red 的value
}
//分組
println map.groupBy {
return it.value.equals('紅色') ? '紅色' : '其他顏色'
}
//添加
map.put('blue', '綠色')
map.green = '灰色'
map.data = [a: 0, b: 1];
println map
println map.getClass() //默認是 LinkerHash , 在定義的時候 通過 as HashMap 可轉爲 HashMap
//遍歷
map.each {
def m ->
println m.key + "----" + m.value
}
//帶下表的變量
map.eachWithIndex { Map.Entry<String, String> entry, int i ->
println "index ${i}" + entry.key + "----" + entry.value
}
map.each {
key, value ->
println key + "----" + value
}
//排序
println map.sort()
println map.sort {
s1, s2 ->
return s1.key < s2.key ? 0 : -1
}
以上爲最常見的使用
範圍
//定義
def range = 1..29
println range[0]//獲取
println range.contains(15) //是否包含
println range.from //開始
println range.to //結束
//遍歷
range.each {
print it
}
println ""
for (i in range) {
print i
}
println ""
//在 switch 中使用
def sh = {
int x ->
def result = 0;
switch (x) {
case 0..10:
result = 1;
break
case 10..20:
result = 2;
break
case 20..30:
result = 3;
break
}
return result;
}
println sh.call(20)
public interface Range<T extends Comparable> extends List<T> {
......
}
其實 Range 是 繼承自 List。所以 List 有的方法他都有。