主要寫的是 Java 和 Groovy 的差異,和 Java 一樣就不寫了
※Eclipse 安裝環境
Help -> About Eclipse 查自己的版本
然後到
這裡,標題為Releases,複製對應自己版本的 Release Update Site
然後回到 Eclipse,選 Help - > Install New Software,然後如下操作:
※選左上角的 Add 後,會跳出一個視窗, Name 隨便打,Location 將剛剛複製的貼進去
※詳細差在哪我不知道,反正我是全選了,安裝要一段時間,安裝好後會提示重啟 Eclipse
※IntelliJ、Android Studio
安裝好 IntelliJ 或 Android Studio 就有環境可測試了(較舊的沒有),如下圖:
※但是這只是測試用而已,如果想使用 Groovy 的專案,還要去官網下載 groovy 的 SDK 來用,如果安裝好了,可以 New -> Groovy Script,如 xxx.Ooo,這將會創建一個 package 為 xxx,而 Ooo.groovy 為檔名
※要注意 jvm 版本和安裝時預設雖然有勾環境變數,但會有「~」的路徑,我沒試過可不可以,反正我是改成正確的路徑,最後 New -> Project 如下設定即可(但 Android Studio 我不知道):
如果忘記選 Groovy library,還可以如下設定:
※有成功才會在左邊的 External Libraries 有 groovy-xxx的東西,沒有就要在右邊的 Add Framework Support 裡面去勾選了,右邊的是按 TestGroovy 按右鍵出來的
※預設import
java.io.*
java.lang.*
java.math.BigDecimal
java.math.BigInteger
java.net.*
java.util.*
groovy.lang.*
groovy.util.*
import static Calendar.getInstance as now
※import static 比 Java 多個 as 的別名功能
※class 的省略
class Person {
String name
String greet(String otherPerson) {
Integer i = 88;
def j = 11;
println i + j
"Hello ${otherPerson}"
}
static void main(String... args){
println new Person().greet("xxxxxxxxxxxxxxxxxx")
}
}
※最後可不加「;」
1.回傳值可不用寫 return 關鍵字
2.宣告多一個 def,如 def i = 0;、def s = 'xxx',轉換後為 Object
/* class */
3.如果屬性前面沒有修飾子(同package),轉換後的 class 其實會幫我們加上 private,並給 setter/getter,但如果自己加 private,就不會提供 setter/getter,不管是不是 static 都會這樣
4.方法、class、建構子,修飾子不寫和寫 public 一樣,而方法不管是不是 static 也是一樣,所以 main 方法可以不寫 public
5.雖然已安裝 java8,還是不能寫 lambda 表達式和 reference method(::)
/* interface */
6.只能定義 public 和不寫,但轉換後都是不寫的
7.雖然已安裝 java8,也是不能在裡面定義 static 方法和 default 關鍵字,我試的是 2.5.1 版本
如果一定要使用 java8 的 default,groovy 有一種很像 interface 的 Type,叫做 trait,轉換後也是 interface,可參考
官網的教學,或者
這篇簡而有力的教學
8.System.out.println 只寫 println 即可,() 可省略(在 groovy 中,只要是有參數的都可省略),但 println 是 groovy 的,可按 ctrl + 滑鼠左鍵進去看
9.預設改 private 後,轉換後也確實是 private,但還是抓的到
10.看 groovy 幫我們的代碼轉成什麼樣子
※在 out 資料夾裡有轉變後的 class,注意如果有修改,要執行完才會重新生成
可以看到都會實作一個叫 GroovyObject 的介面
※六種字串
// 1.單引號
println 'ab' == 'a' + 'b' // true,這個才是和java的 「"」一樣
// 2.雙引號
def x = 'xxx'
println "x is ${x}" /* x is xxx,多了打變數的功能,「{}」可省略
類似ES6的「`」,想打「$」,用跳脫字元「\」*/
// 3.三個單引號
def o = '''a
b
c
d'''
println o // 有換行效果,類似HTML的 <pre>
// 4.三個雙引號
def o = """a
b
${x}
d""" // 三個「'」加上抓變數的功能
// 5.正斜線
/.../
用「/」包起來,可以有以上的所有功能
// 6.錢符號正斜線
$/.../$
和/../很像,差在跳脫字元的不同,這個跳脫字元是「$」,其他都是「\」
println /\//; // /
println $///$; // /
println /$/; // $
println $/$$/$; // $
※使用雙引號,而且有使用到變數,會自動轉為 org.codehaus.groovy.runtime.GStringImpl,可以印出 .class 查看
※如果有一個方法定義參數為 String,GString 可以傳的進來,但相反不行
※方法
package script
final def me = "me!"
final def test = "look ${me}"
println "1 + 1 = ${1+1}" // 1 + 1 = 2
println echo('xxx') // a xxx
println echo("xxx") // a xxx
println echo(test) // b look me!
String echo(m) {
"a ${m}"
}
String echo(GString m) {
"b ${m}"
}
String echo(String m) {
"c ${m}"
}
※a 方法省略了 def 關鍵字,而這三個方法都省略了 return 關鍵字
※a 方法在沒有明確的型態對應時才會呼叫的到,如將 c 刪除就呼叫的到
※如果 test 變數沒有使用到變數(${me}),那會是 String,有用到變數才是 GString
※groovy 就算寫 void,還是會有回傳值 null,但 void 關鍵字不能省略
※方法的括號可省略
echo 'xxx'
def echo(String m) {
println "${m}"
}
getList([1, 2, 3])
getList Arrays.asList(1, 2, 3)
getList Stream.of(1, 2, 3).collect(Collectors.toList())
getArray(['a', 'b', 'c'] as String[])
getArray 'a', 'b', 'c'
String[] array = new String[3]
array[0] = 'a'
array[1] = 'b'
array[2] = 'c'
getArray array
getMap([a: 1, b: 2, c: 3])
getMap(a: 1, b: 2, c: 3)
getMap a: 1, b: 2, c: 3
def getList(List<Integer> list) {
println "a ${list}"
}
def getArray(String[] array) {
println "b ${array}"
}
def getMap(Map<String, Integer> map) {
println "c ${map}"
}
※只有完全沒參數才一定要(),否則都可省略,但要注意閉包可以提出去的問題,假設有個方法有兩個參數,最後一個是閉包,提出去時不能省略(),想省略只能想在()裡面
※集合使用到 groovy 的寫法時,只有 Map 可省略() 和 []
※給陣列傳參數時,不能寫 new String[] {xxx, xxx} 的方式,因為 groovy 會以為是閉包
※集合
// List、Set、Array
def list = [1, 2, 3]
println list
println list instanceof List
println list instanceof LinkedList
println list.size()
list << 4 // 除了add方法外,用這個符號也能增加元素
def linkList = [1, 2, 3] as LinkedList
println linkList instanceof List
println linkList instanceof LinkedList
def set = [3, 2, 3] as Set
println set instanceof Set
String[] sArray =['Ananas', 'Banana', 'Kiwi']
def sArray =['Ananas', 'Banana', 'Kiwi'] as String[]
def intArray = [1, 2, 3] as int[]
// Map
def map = [:] // 宣告空的 map
println map // [:]
println map.isEmpty() // true
map."a" = "aaa" // key 有沒有用「"」包起來都是可以的
map << [c:"ccc"]
map.put("d", "ddd") // 這個和之前一樣,key還是要用「"」包起來
println map // [a:aaa, c:ccc, d:ddd]
println map.a // aaa
println map['a'] // aaa
println map["a"] // aaa
def m = [b:"bbb"] // 非空的 map
println m // [b:bbb]
println m.b // bbb
m.xxx = [b:"bbb"]
println m.toMapString() // [b:bbb, xxx:[b:bbb]],Map 中的 Map
println m.xxx.b // bbb
println m.class // null,因為沒有class這個key
println m.getClass() // class java.util.LinkedHashMap
※增加元素都可以用「<<」
※運算符、三元運算子
println 2 ** 10 // 1024,2的10次方
def f = 2
println f ** 5 // 32,2的5次方
println f **= 5 // 32,f = f ** 5
def x = 1;
println x == 1 ?: "sucess" // 「?:」不能分開,?:之間沒寫預設是 true
※?:最後的 else 一定要寫
※基本型態的後綴
Java 只有 L、F、D 來代表 Long、Float、Double,大小寫都可以
Groovy 多兩個 I 和 G,一樣大小寫都可以,i 表示 Integer;G 代表有兩個 BigInteger、BigDecimal
例:
def long = 999L
def xxx = 555I
def ooo = 548G
※最好用大寫,避免和數字混淆
※groovy 中沒有基本型態,雖然可以宣告,但用 class 去查看,會發現都是 Wrapper 類別
※使用 def 時,預設宣告整數為 Integer,有小數點的為 BigDecimal(就算是1.0也是一樣)
※?.
String result = null
println result?.toUpperCase()
※可防止 NullPointerException,回傳 null
※@field
class User {
String name = 'xxx'
String getName() {
println 'ooooooooooooo'
this.name
}
}
println new User().@name
※可以直接專取屬性,不加 @ 會呼叫 getter
※&method
def str = 'xxx'
def result = str.&toUpperCase //一定要用def接
println result()
def xxx(String str) { str.toLowerCase()}
def xxx(Integer x) { 2 * x }
def ref = this.&xxx
println ref('xOx') // xox
println ref(123) // 246
※使用「.&」宣告完,可以當方法呼叫,但要注意 &後面的方法沒有 ()
class Ooo {
int count = 0
def xxx() {
return ++this.count
}
}
def ref = new Ooo().&xxx
println ref() // 1
println ref() // 2
※這個有點像 javascript 的閉包功能
※*.
class Car {
String make
String model
}
def cars = [
new Car(make: 'Peugeot', model: '508'),
new Car(make: 'Renault', model: 'Clio')
]
def makes = cars*.make
println makes == ['Peugeot', 'Renault'] // true
println makes instanceof List // true
※只取集合的某個屬性
※延伸方法參數
int function(int x, int y, int z) {
x*y+z
}
def args = [4,5,6]
println function(*args) // 26
※
※延伸操作-集合
def items = [4,5,2]
def list = [1,2,3,*items,6]
println list == [1,2,3,4,5,2,6] // true
def set = [1,2,3,*items,6] as Set
println set == [1,2,3,4,5,6] as Set // true
def m1 = [c:3, d:4]
def map = [a:1, b:2, *:m1]
println map == [a:1, b:2, c:3, d:4]
※
※範圍操作
def range = 0..3
println range // [0, 1, 2, 3]
println (1..3).collect() // [1, 2, 3]
println (1..<3).collect() // [1, 2],只有小於,也只能寫在後面
println ('a'..'d').collect() //[a, b, c, d]
println range.contains(3) // true,包括3這個元素嗎?
println range.contains('3') // false,包括3這個元素嗎?
println range.contains(4) // false
println range.from // 0,第一個元素
println range.to // 3,最後一個元素
def r = 0..30
def n = r.by(3)
n.each {
print "${it} " // 0 3 6 9 12 15 18 21 24 27 30
}
/* 簡化
(0..30).by(3).each {
print "${it} "
}
*/
※<和3中間可以空格
※Range 為 List 的子類,都是 interface,Range 有四個實作類 EmptyRange, IntRange, NumberRange, ObjectRange
※太空船操作
println 1 <=> 1 // 0,相等
println 1 <=> 3 // -1,左邊小於右邊
println 3 <=> 1 // 1,左邊大於右邊
println 'a' <=> 'z'// -1
println 1.compareTo(1) // 0
println 1.compareTo(3) // -1
println 3.compareTo(1) // 1
println 'a'.compareTo('z') // -25
※可能 <==> 長得像太空船吧!
※1就是 true;-1就是 false
※正則
package script
import java.util.regex.Matcher
import java.util.regex.Pattern
def p1 = ~/^foo.*/ // 以 foo 開頭的
def p2 = ~'.*foo$' // 以 foo 結尾的
def p3 = ~"(foo){2}" // 剛好是兩個 foo 的
def p4 = ~$/foo/$ // 只能是 foo 的
println p1 instanceof Pattern
println p1.matcher('foo123').matches()
println p2.matcher('123foo').matches()
println p3.matcher('foofoo').matches()
println p4.matcher('foo').matches()
def text = "xxx"
def m = text =~ /xxx/
println m instanceof Matcher
println m.matches()
if (m.matches()) { // 官網直接判斷m而已,說會呼叫find(),但我試的結果永遠為true
println '有匹配到'
} else {
println '沒匹配到'
}
println m.matches() ? 'o' : 'x'
def t = 'ooo'
def mat = t ==~ /ooo/
println mat instanceof Boolean
println mat
if (mat) {
println '有匹配到'
} else {
println '沒匹配到'
}
println mat ?:false
※主要就是 ~/.../ 為 Pattern; =~ 為 Matcher; ==~ 為 Boolean
※/.../ 後面和 javascript 不一樣,沒有什麼 gim 的
※範圍操作-集合
def list = [0,1,2,3,4]
println list[2] == 2 // true
list[2] = 4
println list[0..2] == [0,1,4] // true
list[0..2] = [6,6,6]
println list == [6,6,6,3,4] // true
※
※閉包
def closure1 = {
-> println "xxx" // xxx
}
closure1.call() // call 可以省略
def closure2 = { i, p ->
println "${i}, ${p}" // 5, ooo
}
closure2(5, "ooo")
def closure3 = {
println it // 是我, it為內鍵變數
}
closure3("是我")
※一定要用 def 宣告
※使用 -> 將參數和實作隔開,但如果沒有參數,可以省略 ->
※和 java8 的 lambda 不太一樣,參數永遠沒有「()」
※如果只有一個參數,可以使用 it 這個內鍵變數
※參數的型態和 lambda 一樣,通通可以省略,相當於是 def,但如果有寫,如 String,那就要乖乖傳 String 進去
※一定有回傳值,沒有就是 null,像 println 回傳 void,所以是 null,return 關鍵字可以不寫,所以假設最後一行寫 'xxx',那回傳的就是 xxx
※return 可以不寫在最後一行,但 return 之後的程式碼不會執行
※閉包的循環
[1,2,3,4,5].each { print "${it}"} // 12345
println ''
['a':1,'b':2,'c':3].each { print "${it}-"} // a=1-b=2-c=3-
println ''
['a':1,'b':2,'c':3].each { print it.key+":"+it.value} // a:1b:2c:3
println ''
※