Groovy入门(一)—— Groovy语法

Groovy语法

1. 注释

1.1. 单行注释

Groovy单行注释以//开头,可以出现在程序的各个位置。

// a standalone single line comment
println "hello" // a comment till the end of the line

1.2. 多行注释

多行注释以 /* 开头,以 */ 结尾,可以出现在程序的任何位置。

/* a standalone multiline comment
   spanning two lines */
println "hello" /* a multiline comment starting
                   at the end of a statement */
println 1 /* one */ + 2 /* two */

1.3. GroovyDoc

GroovyDoc以 /** 开头,以 */结尾,中间行一般可以选择性的以 * 开头。

GroovyDoc一般用于:

  • 类型定义 (classes, interfaces, enums, annotations)
  • 字段或属性定义
  • 方法定义
/**
 * A Class description
 */
class Person {
    /** the name of the person */
    String name
    /**
     * Creates a greeting method for a certain person.
     *
     * @param otherPerson the person to greet
     * @return a greeting message
     */
    String greet(String otherPerson) {
       "Hello ${otherPerson}"
    }
}

1.4. Shebang line

#开头写在文件的第一行,告诉Unix或类Unix系统以何种解释器去运行脚本。前提是已经安装了Groovy,并且配置完PATH。

#!/usr/bin/env groovy
println "Hello from the shebang line"

2. 关键字

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

3. 标识符

3.1. 普通标识符(Normal identifiers)

标识符以字母、$、_开头,不能以数字开头,但后面可以跟数字。

字母的的取值区间为:

  • 'a' to 'z' (lowercase ascii letter)
  • 'A' to 'Z' (uppercase ascii letter)
  • '\u00C0' to '\u00D6'
  • '\u00D8' to '\u00F6'
  • '\u00F8' to '\u00FF'
  • '\u0100' to '\uFFFE'

eg:

def name
def item3
def with_underscore
def $dollarStart

3.2. 引用标识符(Quoted identifiers)

引用标识符是.(dot)后的表达式。比如说nameperson.name的一部分,那么我们可以通过person."name"或者person.'name'来引用它。这点与Java不同,Java不允许这种格式的引用。eg:

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"

Groovy提供了不同种类的字符串字面量,所有String类型的字面量都允许写到.后作为引用标识符。eg:

map.'single quote'
map."double quote"
map.'''triple single quote'''
map."""triple double quote"""
map./slashy string/
map.$/dollar slashy string/$

4. String

Groovy支持java.lang.String和GString(groovy.lang.GString)字符串类型,其中GString在一些编程语言中被称作interpolated stringsWikipedia - String interpolation

4.1. 单引号字符串(Single quoted string)

单引号字符串被解释成java.lang.string,不支持内插值。

'a single quoted string'

4.2. 字符串拼接

Groovy中连接字符串使用+

assert 'ab' == 'a' + 'b'

4.3. 三单引号字符串(Triple single quoted string)

三单引号字符串被解释成java.lang.String类型,不支持内插值。

三单引号支持多行,支持文本跨行,并且不需要换行符,字符串原样输出。eg:

def aMultilineString = '''line one
line two
line three'''

通常,代码在格式化完毕之后,会保持缩进。对于三单引号字符串来说,会把缩进也原样输出。Groovy提供了String#stripIndent()方法来去掉字符串前的缩进,并且提供了String#stripMargin()方法,可以删除字符串开始位置的指定分隔符。

当我们创建如下的字符串时:

def startingAndEndingWithANewline = '''
line one
line two
line three
'''

会发现字符串开头包含一个换行符\n,可以通过字符串开头添加``来消除开头的换行符。

def strippedFirstNewline = '''\
line one
line two
line three
'''
assert !strippedFirstNewline.startsWith('\n')

4.4. 双引号字符串

"a double quoted string"

当双引号字符串中没有插值表达式时,字符串的类型为java.lang.String,当双引号字符串中包含插值表达式时,字符串类型为groovy.lang.GString

4.4.1 字符串插值(String interpolation)

除了单引号字符串和三单引号字符串以外,任何Groovy表达式可以出现在所有的字符串字面量中。插值实际上是替换字符串中的占位符。占位符表达式是被${}围绕或以$为前缀的点表达式(dotted expressions),当GString传递给一个以String类型作为参数的方法时,会调用toString方法,将占位符替换为表达式所代表的值。eg:

def name = 'Guillaume' // a plain string
def greeting = "Hello ${name}"
assert greeting.toString() == 'Hello Guillaume'
def sum = "The sum of 2 and 3 equals ${2 + 3}"
assert sum.toString() == 'The sum of 2 and 3 equals 5'

实际上${}中不仅可以使用表达式,也可以写声明语句,但是这些语句的返回值为null,例如"The sum of 1 and 2 is equal to ${def a = 1; def b = 2; a + b}"在Groovy中是被支持的,但是一般在Groovy中不推荐这样写。更好的写法是在GString中只使用简单的占位符。

使用$点表达式(dotted expressions),eg:

def person = [name: 'Guillaume', age: 36]
assert "$person.name is $person.age years old" == 'Guillaume is 36 years old'

使用$点表达式(dotted expressions)的时候,只允许a.ba.b.c的写法,不能调用方法,否则会抛出groovy.lang.MissingPropertyException的异常。因为Groovy在替换插值时调用的是toString方法。

def number = 3.14

shouldFail(MissingPropertyException) {
    println "$number.toString()" // groovy.lang.MissingPropertyException
}

"$number.toString()" 替换为 "${number.toString}()" 可以正常运行。

4.4.2. 特殊的插值闭包表达式(Special case of interpolating closure expressions)

闭包表达式的格式为:${->},简单的理解为一个闭包前面加了一个$符号。eg:

def sParameterLessClosure = "1 + 2 == ${-> 3}" 
assert sParameterLessClosure == '1 + 2 == 3'

def sOneParamClosure = "1 + 2 == ${ w -> w << 3}" 
assert sOneParamClosure == '1 + 2 == 3'

关于闭包表达式:

  • 闭包是无参的
  • 闭包包含一个java.io.StringWriter参数,可以通过追加内容到>>后面的方式添加。

闭包表达式只能有0个或1个参数。

闭包表达式和普通表达式唯一的不同是:lazy evaluation 。详情移步 —> Wikipedia - Lazy evaluation

def number = 1 
def eagerGString = "value == ${number}"
def lazyGString = "value == ${ -> number }"

assert eagerGString == "value == 1" 
assert lazyGString == "value == 1" 

number = 2 
assert eagerGString == "value == 1" // eagerGString不会再次求值
assert lazyGString == "value == 2"  // lazyGString会再次求值
4.4.3. GString and String hashCodes

尽管GString可以代替String,但是他们还一处不同:他们的hashCodes不同。原生的Java String 是immutable(不可变的),但是GString所表示的String却是可变的,依赖于的它的插值。即使GString和Java原生String类型有相同的字面量,它们的hashCodes的值可能不同。eg:

assert "one: ${1}".hashCode() != "one: 1".hashCode()

由于GString和String的hashCodes不同,所以应该避免使用使用GString作为Map的key。eg:

def key = "a"
def m = ["${key}": "letter ${key}"]     
assert m["a"] == null

4.5. 三双引号字符串( Triple double quoted string)

类似于三单引号字符串,支持跨行。也类似双引号字符,支持GString插值操作。

def name = 'Groovy'
def template = """
    Dear Mr ${name},
    You're the winner of the lottery!
    Yours sincerly,
    Dave
"""

assert template.toString().contains('Groovy')

4.6. Slashy string

/作为界定符的字符串,叫做Slashy string。它通常被用于写正则表达式,因为不需要转译的反斜线``。

def fooPattern = /.*foo.*/
assert fooPattern == '.*foo.*'

如果字符串中间出现/,这种情况下才需要转译。eg:

def escapeSlash = /The character \/ is a forward slash/
assert escapeSlash == 'The character / is a forward slash'

Slashy string允许跨行,eg:

def multilineSlashy = /one
    two
    three/

assert multilineSlashy.contains('\n')

Slashy string支持插值操作,类似GString。eg:

def color = 'blue'
def interpolatedSlashy = /a ${color} car/

assert interpolatedSlashy == 'a blue car'

如果Slashy string是空字符串//,那么编译过程中会把//当做注释。

4.7. Dollar slashy string

Dollar slashy string相当于跨行的GString,以$/开头,以/$结尾。以$作为转译字符,可以转译另一个$/

4.8. 字符(Characters)

Groovy没有明确的字符类型,可以通过以下三种方式创建:

char c1 = 'A'  // 类型声明为char
assert c1 instanceof Character 

def c2 = 'B' as char  // 通过as将类型强制指定为char
assert c2 instanceof Character

def c3 = (char)'C'  // 通过类型转换
assert c3 instanceof Character

5. 数值(Numbers)

5.1. 整型(Integral literals)

Groovy的整型和Java类似:

  • byte
  • char
  • short
  • int
  • long
  • java.lang.BigInteger

eg:

// 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

其它进制:

  • 2进制是以0b开头的数字
  • 8进制是以0开头的数字
  • 16进制是以0x开头的数字

5.2. 浮点数(Decimal literals)

浮点数类型和Java类似:

  • float
  • double
  • java.lang.BigDecimal

浮点数类型支持指数,通过eE实现。

// primitive types
float f = 1.234
double d = 2.345

// infinite precision
BigDecimal bd = 3.456

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作为浮点数的默认类型。除非显示的声明floatdouble,否则浮点数类型为java.lang.BigDecimal。尽管如此,在一些接受参数为floatdouble的方法中,依然可以使用BigDecimal类型作为参数传递。

5.3. 数值中使用下划线

当数值过长的时候,可以使用_对数字进行分组,以使阅读更加简洁明了。eg:

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

5.4. 数值类型后缀(Number type suffixes)

可以通过使用后缀来指定数字类型

  • BigInteger类型后缀为Gg
  • Long类型后缀为Ll
  • Integer类型后缀为Ii
  • Bigdecimal类型后缀为Gg
  • Double类型后缀为Dd
  • Float类型后缀为Ff

eg:

assert 42I == new Integer('42')
assert 42i == new Integer('42') // lowercase i more readable
assert 123L == new Long("123") // uppercase L more readable
assert 2147483648 == new Long('2147483648') // Long type used, value too large for an Integer
assert 456G == new BigInteger('456')
assert 456g == new BigInteger('456')
assert 123.45 == new BigDecimal('123.45') // default BigDecimal type used
assert 1.200065D == new Double('1.200065')
assert 1.234F == new Float('1.234')
assert 1.23E23D == new Double('1.23E23')
assert 0b1111L.class == Long // binary
assert 0xFFi.class == Integer // hexadecimal
assert 034G.class == BigInteger // octal

6. Boolean

布尔类型是一种特殊的类型用于判断对或错:truefalse。Groovy有一套特别的规则用于强制将non-boolean类型转换为bollean类型。

7. List

Groovy中没有定义自己的List类型,使用的是java.util.List类型。通过一对[]包括,里面的元素以,分隔来定义一个List。默认情况下,创建的List的类型为java.util.ArrayList。eg:

def numbers = [1, 2, 3]         

assert numbers instanceof List  
assert numbers.size() == 3

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

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

通过使用as操作符可以强制指定List的类型,或者在声明List变量时强制指定类型。eg:

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]          
assert otherLinked instanceof java.util.LinkedList

可以使用[]获取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']

8. 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数组的初始化方式。

9. Maps

Map定义方式为:使用[]包括,里面的元素为key/value的形式,key和value以:分隔,每一对key/value以逗号分隔。Groovy穿件的map默认类型为java.util.LinkedHashMap。eg:

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。

当我们使用数字作为key时,这个数字可以明确的认为是数字,并不是Groovy根据数字创建了一个字符串。但是如果以一个变量作为key的话,需要将变量用()包裹起来,否则key为变量,而不是变量所代表的值。eg:

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')    
assert !person.containsKey('key')


作者:losemycat
链接:http://www.jianshu.com/p/f02b066bb055
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
展开阅读全文

没有更多推荐了,返回首页