Groovy入門 | 基礎語法

Java的東西Groovy都能用,包括語法和類庫

public static void main(String[] args) {
    // 重要的事情說3遍
    for (int i = 0; i < 3; i++) {
        System.out.println("Java的東西Groovy都能用");
    }
    // 再3遍
    for (i in 0..2) {
            println 'Java的東西Groovy都能用'
    }
    // 又3遍
    3.times {
            println 'Java的東西Groovy都能用'
    }
}
  1. Groovy繼承了Java的所有東西,就是你突然忘了Groovy的語法可以寫成Java代碼,也就是Groovy和Java混在一起也能執行。
  2. Groovy和Java一樣運行在JVM,源碼都是先編譯爲class字節碼。
  3. Groovy又對Java的語法進行了簡化,功能進行了擴充。

自動導入常用包

java.lang
java.util
java.io
java.net
java.math.BigDecimal
java.math.BigInteger
groovy.lang
groovy.util

語句不需要分號結尾

寫了也沒事

註釋

// 單行註釋
println "hello groovy,"
/*
多行註釋
*/
+ "I'm Atlas."

關鍵字

as、assert
break
case、catch、class、const、continue
def、default、do
else、enum、extends
false、finally、for
goto
if、implements、import、in、instanceof、interface
new、null
package
return
super、switch
this、throw、throws、trait、true、try
while

def 和類型

  1. def可以聲明任何類型的變量。
  2. def定義帶有無類型參數的方法時

可以這樣:

void doSomething(def param1, def param2) { }

也可以這樣:

void doSomething(param1, param2) { }

訪問修飾符默認採用 public

Groovy的類和方法的默認修飾符都是public,且可以省略不寫。由於修飾符可以省略、方法返回類型可以省略、方法參數類型可以省略。所以Java的類和main方法的結構可以簡化爲:

class HelloGroovy {
    static main(args) {
    }
}

可選擇性使用的 return 關鍵字

String toString() { return "a server" }
//可寫成:
String toString() { "a server" }

省略括號

對於頂級表達式,Groovy 允許省去括號,比如 println 命令:

println "Hello"

標識符

  1. 標識符以字母、$、_開頭,不能以數字開頭,但後面可以跟數字。
  2. 字母的的取值區間爲:
    'a' to 'z' (lowercase ascii letter)
    'A' to 'Z' (uppercase ascii letter)
    '\u00C0' to '\u00D6'
    '\u00D8' to '\u00F6'
    '\u00F8' to '\u00FF'
    '\u0100' to '\uFFFE'
  3. Groovy提供了不同種類的字符串字面量,所有String類型的字面量都允許寫到.後作爲引用標識符。
def map = [:]
map."an identifier with a space and double quotes" = "ALLOWED"
map.'with-dash-signs-and-single-quotes' = "ALLOWED"
assert map."an identifier with a space and double quotes" == "ALLOWED"
assert map.'with-dash-signs-and-single-quotes' == "ALLOWED"
map.'single quote'
map."double quote"
map.'''triple single quote'''
map."""triple double quote"""
map./slashy string/
map.$/dollar slashy string/$

字符串

char c1 = 'A'  // 類型聲明爲char
assert c1 instanceof Character

def c2 = 'B' as char  // 通過as將類型強制指定爲char
assert c2 instanceof Character

def c3 = (char)'C'  // 通過類型轉換
  • 單引號是輸入什麼就是什麼。
// 單引號
println('a single quoted string')
assert 'ab' == 'a' + 'b'

執行結果爲:

a single quoted string
  • 三引號是輸出一段文本,可以直接的加空格和換行。
println('''這是一段文本。
換行啦!!!
    前面有四個空。。。
又換行啦!!!''')

執行結果爲:

這是一段文本。
換行啦!!!
    前面有四個空。。。
又換行啦!!!
  • 雙引號可以用$引用變量的值。
// 雙引號
def name = 'Atlas'
def greeting = "Hello ${name}"
println greeting
assert greeting.toString() == 'Hello Atlas'
def sum = "The sum of 2 and 3 equals ${2 + 3}"
println sum
assert sum.toString() == 'The sum of 2 and 3 equals 5'
def person = [name: 'Guillaume', age: 36]
println "$person.name is $person.age years old"
assert "$person.name is $person.age years old" == 'Guillaume is 36 years old'

執行結果爲:

Hello Atlas
The sum of 2 and 3 equals 5
Guillaume is 36 years old
  • 三雙引號
def name = 'Groovy'
def template = """
    Dear Mr ${name},

    You're the winner of the lottery!

    Yours sincerly,

    Dave
"""
println template
assert template.toString().contains('Groovy')

執行結果爲:

    Dear Mr Groovy,

    You're the winner of the lottery!

    Yours sincerly,

    Dave

數據類型

  • 整型

Groovy的整型和Java類似:

byte
char
short
int
long
java.lang.BigInteger

e.g.

// primitive types
byte  b = 1
char  c = 2
short s = 3
int   i = 4
long  l = 5
// infinite precision
BigInteger bi =  6

如果使用def聲明類型,那麼這個整型是可變的。它會數值的大小來匹配類型。(負數也如此)

def a = 1
assert a instanceof Integer

// Integer.MAX_VALUE
def b = 2147483647
assert b instanceof Integer

// Integer.MAX_VALUE + 1
def c = 2147483648
assert c instanceof Long

// Long.MAX_VALUE
def d = 9223372036854775807
assert d instanceof Long

// Long.MAX_VALUE + 1
def e = 9223372036854775808
assert e instanceof BigInteger

def na = -1
assert na instanceof Integer

// Integer.MIN_VALUE
def nb = -2147483648
assert nb instanceof Integer

// Integer.MIN_VALUE - 1
def nc = -2147483649
assert nc instanceof Long

// Long.MIN_VALUE
def nd = -9223372036854775808
assert nd instanceof Long

// Long.MIN_VALUE - 1
def ne = -9223372036854775809
assert ne instanceof BigInteger
  • 浮點型

浮點數類型和Java類似:

float
double
java.lang.BigDecimal

e.g.

// primitive types
float  f = 1.234
double d = 2.345
// infinite precision
BigDecimal bd =  3.456

浮點數類型支持指數,通過e或E實現。

assert 1e3  ==  1_000.0
assert 2E4  == 20_000.0
assert 3e+1 ==     30.0
assert 4E-2 ==      0.04
assert 5e-1 ==      0.5

爲了計算的準確性,Groovy使用BigDecimal作爲浮點數的默認類型。除非顯示的聲明float或double,否則浮點數類型爲java.lang.BigDecimal。儘管如此,在一些接受參數爲float或double的方法中,依然可以使用BigDecimal類型作爲參數傳遞。

當數值過長的時候,可以使用_對數字進行分組,以使閱讀更加簡潔明瞭。

long creditCardNumber = 1234_5678_9012_3456L
long socialSecurityNumbers = 999_99_9999L
double monetaryAmount = 12_345_132.12
long hexBytes = 0xFF_EC_DE_5E
long hexWords = 0xFFEC_DE5E
long maxLong = 0x7fff_ffff_ffff_ffffL
long alsoMaxLong = 9_223_372_036_854_775_807L
long bytes = 0b11010010_01101001_10010100_10010010

數值類型後綴

BigInteger類型後綴爲G或g
Long類型後綴爲L或l
Integer類型後綴爲I或i
Bigdecimal類型後綴爲G或g
Double類型後綴爲D或d
Float類型後綴爲F或f
  • Boolean

布爾類型是一種特殊的類型用於判斷對或錯:true或false。Groovy有一套特別的規則用於強制將non-boolean類型轉換爲bollean類型。

  • List

Groovy中沒有定義自己的List類型,使用的是java.util.List類型。通過一對[]包括,裏面的元素以,分隔來定義一個List。默認情況下,創建的List的類型爲java.util.ArrayList。

def numbers = [1, 2, 3]
assert numbers instanceof List
assert numbers.size() == 3

List中元素可以是不同類型:

def heterogeneous = [1, "a", true]

通過使用as操作符可以強制指定List的類型,或者在聲明List變量時強制指定類型。

def arrayList = [1, 2, 3]
assert arrayList instanceof java.util.ArrayList
def linkedList = [2, 3, 4] as LinkedList
assert linkedList instanceof java.util.LinkedList
LinkedList otherLinked = [3, 4, 5]

可以使用[]獲取List中的元素,可以使用<<向list末尾追加元素。

def letters = ['a', 'b', 'c', 'd']
assert letters[0] == 'a'
assert letters[1] == 'b'
assert letters[-1] == 'd'
assert letters[-2] == 'c'
letters[2] = 'C'
assert letters[2] == 'C'
letters << 'e'
assert letters[ 4] == 'e'
assert letters[-1] == 'e'
assert letters[1, 3] == ['b', 'd']
assert letters[2..4] == ['C', 'd', 'e']
  • Arrays

Groovy定義數組的方式和定義list的方式一樣,只不過聲明時需要制定類型,或者通過as來強制制定類型爲Array。

String[] arrStr = ['Ananas', 'Banana', 'Kiwi']
assert arrStr instanceof String[]
assert !(arrStr instanceof List)
def numArr = [1, 2, 3] as int[]
assert numArr instanceof int[]
assert numArr.size() == 3
//多維數組
def matrix3 = new Integer[3][3]
assert matrix3.size() == 3
Integer[][] matrix2
matrix2 = [[1, 2], [3, 4]]
assert matrix2 instanceof Integer[][]

Groovy不支持Java數組的初始化方式。

  • Maps

Map定義方式爲:使用[]包括,裏面的元素爲key/value的形式,key和value以:分隔,每一對key/value以逗號分隔。Groovy穿件的map默認類型爲java.util.LinkedHashMap。

def colors = [red: '#FF0000', green: '#00FF00', blue: '#0000FF']
assert colors['red'] == '#FF0000'
assert colors.green == '#00FF00'
colors['pink'] = '#FF00FF'
colors.yellow = '#FFFF00'
assert colors.pink == '#FF00FF'
assert colors['yellow'] == '#FFFF00'
assert colors instanceof java.util.LinkedHashMap

Map中通過[key]或.key的方式來獲取key對應的value。如果key不存在,則返回null。

assert colors.unknown == null

當我們使用數字作爲key時,這個數字可以明確的認爲是數字,並不是Groovy根據數字創建了一個字符串。但是如果以一個變量作爲key的話,需要將變量用()包裹起來,否則key爲變量,而不是變量所代表的值。

def key = 'name'
def person = [key: 'Guillaume']     // key實際上爲"key"
assert !person.containsKey('name')
assert person.containsKey('key')
person = [(key): 'Guillaume']    // key實際上爲"name"
assert person.containsKey('name')
  • Range
/ 範圍從1到10
def demoRange = 1..10
// 範圍從1到9
def demoRange2 = 1..<10
println(demoRange2.from) // 獲取起始值
println(demoRange2.to) // 獲取最大值

閉包

閉包是一段代碼塊,注意閉包也是數據類型,所以可以把閉包作爲方法的參數或者返回類型。 如果我們要篩選指定數n範圍內的奇數,普通寫法如下:

def getOdd(n) {
        for (i in 1..n) {
            if (i % 2 != 0)
                println i
        }
}
getOdd(10)

如果要獲取偶數,又要再寫一個方法:

def getEven(n) {
        for (i in 1..n) {
            if (i % 2 == 0)
            println i
        }
}
getEven(10)

這兩個方法其實for循環部分的內容是重合的。 而如果用閉包就不會這樣了,例如下面的pick接受兩個參數,一個參數n,另外一個是閉包(closure是變量名隨便取)。再重複一遍閉包是一個代碼塊,這裏傳進來你想在遍歷過程做什麼。至於怎麼把便利過程的i傳遞給閉包,閉包有一個隱式變量叫it,可以接收一個參數。
看代碼:

def pick(n, closure) {
        for (i in 1..n) {
            closure(i)
        }
}

// 打印奇數
pick(10, {
    if (it % 2 != 0) // it代表傳進來的參數,也就是上面closure(i)的i
        println it
})

// 打印偶數
pick(10, {
    if (it % 2 == 0)
        println it
})

總之循環結構不需要自己寫了,你只需要寫你想在遍歷過程中做什麼,例如如果要打印全部數的平方可以這樣:

// 平方
pick(10, {
    println it **= 2
})

如果有一些行爲是經常用的,你也給閉包取個名字固定下來啊就像定義變量一樣。例如如果把剛纔的的打印奇數、打印偶數和打印平方定義成變量可以改成這樣:

def pick(n, closure) {
    for (i in 1..n) {
        closure(i)
    }
}
// 打印奇數
def getOdd = {
    if (it % 2 != 0)
        println it
}
// 打印偶數
def getEven = {
    if (it % 2 == 0)
        println it
}
// 打印平方
def getSquare = {
    println it **= 2
}
pick(10, getOdd)
pick(10, getEven)
pick(10, getSquare)

隱式變量it只能代表一個參數吧?閉包怎麼接收多個參數?是這樣的,用 -> 把參數列表和行爲隔開即可。假設我們定義一個閉包接受兩個參數求他們的和:

def getSum = {
    x, y -> println x + y
}
getSum(3, 4) // 閉包可以直接調用

關於閉包還有個說的,就是假設你的閉包不需要接收參數,但是還是會自動生成隱式it,只不過它的值爲null。也就是說,閉包至少包含一個參數。

Getter 與 Setter

不必自己創建字段和 getter/setter,只需把這些活兒留給 Groovy 編譯器即可:

class Person {
    String name
}

編譯後:

public class Person implements GroovyObject {
    private String name;
    public Person() {
        CallSite[] var1 = $getCallSiteArray();
        MetaClass var2 = this.$getStaticMetaClass();
        this.metaClass = var2;
    }
    public String getName() {
        return this.name;
    }
    public void setName(String var1) {
        this.name = var1;
    }
}

相等與 ==

Java 的 == 實際相當於 Groovy 的 is() 方法,而 Groovy 的 == 則是一個更巧妙的 equals()。

要想比較對象的引用,不能用 ==,而應該用 a.is(b)。

斷言

可以使用 assert 語句來檢查參數、返回值以及更多類型的值。與 Java 的 assert 有所不同,Groovy 的 assert 並不需要激活,它是一直被檢查的。

異常捕捉

如果不關心 try 語句塊中所要拋出的異常類型,可以只捕捉異常而忽略它們的類型。所以,像下面這樣的語句:

try {
    // ...
} catch (Exception t) {
    // 一些糟糕的事情
}

就可以變成下面這樣捕捉任何異常(any 或 all 都可以,只要是能讓你認爲是任何東西的詞兒就可以用):

try {
    // ...
} catch (any) {
    // 一些糟糕的事情
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章