// a standalone single line comment println "hello" // a comment till the end of the line
1.注释
1.1. 单行注释
1.2. 多行注释
1.3. GroovyDoc注释
1.4. Shebang线
2.关键词
3.标识符
3.1. 普通标识符
3.2. 带引号的标识符
4.字符串
4.1. 单引号字符串
4.2. 字符串链接
4.3. 三重单引号字符串
4.3.1. 逃避特殊字符
4.3.2. Unicode转义序列
4.4. 双引号字符串
4.4.1. 字符串插值
4.4.2. 插值闭包表达式的特例
4.4.3. 与Java的互操做性
4.4.4. GString和String hashCodes
4.5. 三重双引号字符串
4.6. Slashy string
4.7. 美圆邋string的字符串
4.8. 字符串摘要表
4.9. 人物
5.数字
5.1. 积分文字
5.1.1. 替代的非基础10表示
二进制文字
八进制文字
十六进制文字
5.2. 十进制文字
5.3. 文字中的下划线
5.4. 数字类型后缀
5.5. 数学运算
5.5.1. 除法运算符的状况
5.5.2. 电力运营商的状况
6.布尔
7.列表
8.数组
9.maphtml
本章介绍Groovy编程语言的语法。语言的语法源自Java语法,但使用Groovy的特定构造对其进行了加强,并容许某些简化。java
单行注释以行开头,//
能够在行中的任何位置找到。//
直到行尾的字符被视为注释的一部分。正则表达式
// a standalone single line comment println "hello" // a comment till the end of the line
多行注释以行开头,/*
能够在行中的任何位置找到。如下字符/*
将被视为注释的一部分,包括换行符,直到第一个*/
结束注释。所以,多行注释能够放在语句的末尾,甚至能够放在语句中。express
/* a standalone multiline comment spanning two lines */ println "hello" /* a multiline comment starting at the end of a statement */ println 1 /* one */ + 2 /* two */
与多行注释相似,GroovyDoc注释是多行的,但从一开始就/**
结束*/
。第一个GroovyDoc注释行后面的行能够选择以星号开头*
。这些注释与:编程
类型定义(类,接口,枚举,注释),api
字段和属性定义数组
方法定义闭包
虽然编译器不会抱怨GroovyDoc注释与上述语言元素没有关联,可是你应该在它以前添加带有注释的那些结构。oracle
/** * 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}" } }
GroovyDoc遵循与Java本身的JavaDoc相同的约定。所以,您将可以使用与JavaDoc相同的标记。编程语言
除了单行注释以外,还有一个特殊的行注释,一般称为UNIX系统能够理解的shebang行,它容许脚本直接从命令行运行,只要您已经安装了Groovy发行版而且该groovy
命令可用于PATH
。
#!/usr/bin/env groovy println "Hello from the shebang line"
该# 字符必须是文件的第一个字符。任何缩进都会产生编译错误。 |
如下列表表示Groovy语言的全部关键字:
Table 1. Keywords
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
|
标识符以字母,美圆或下划线开头。他们不能以数字开头。
一个字母能够是如下范围内:
'a'到'z'(小写ascii字母)
'A'到'Z'(大写ascii字母)
'\ u00C0'到'\ u00D6'
'\ u00D8'到'\ u00F6'
'\ u00F8'到'\ u00FF'
'\ u0100'到'\ uFFFE'
而后跟随字符能够包含字母和数字。
如下是有效标识符的一些示例(此处为变量名称):
def name def item3 def with_underscore def $dollarStart
但如下是无效的标识符:
def 3tier def a+b def a#b
跟在点后的全部关键字也都是有效的标识符:
foo.as foo.assert foo.break foo.case foo.catch
带引号的标识符出如今虚线表达式的点后面。例如,表达式的name
一部分person.name
能够用person."name"
或引用person.'name'
。当某些标识符包含Java语言规范禁止但在引用时Groovy容许的非法字符时,这一点尤为有趣。例如,短划线,空格,感叹号等字符。
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提供了不一样的字符串文字。点后实际容许全部类型的字符串:
map.'single quote' map."double quote" map.'''triple single quote''' map."""triple double quote""" map./slashy string/ map.$/dollar slashy string/$
普通字符串和Groovy的GStrings(插值字符串)之间存在差别,由于在后一种状况下,插值将插入到最终字符串中以评估整个标识符:
def firstname = "Homer" map."Simpson-${firstname}" = "Homer Simpson" assert map.'Simpson-Homer' == "Homer Simpson"
文本文字以称为字符串的字符串的形式表示。Groovy容许您实例化java.lang.String
对象,以及GStrings(groovy.lang.GString
),它们在其余编程语言中也称为插值字符串。
单引号字符串是由单引号括起来的一系列字符:
'a single quoted string'
单引号字符串是普通的java.lang.String ,不支持插值。 |
全部Groovy字符串均可以与+
运算符链接:
assert 'ab' == 'a' + 'b'
三重单引号字符串是由单引号三元组包围的一系列字符:
'''a triple single quoted string'''
三重单引号字符串是普通的java.lang.String ,不支持插值。 |
三重单引号字符串是多行的。您能够跨越行边界跨越字符串的内容,而无需将字符串拆分为多个部分,而不使用链接或换行转义字符:
def aMultilineString = '''line one line two line three'''
若是您的代码是缩进的,例如在类方法的主体中,则字符串将包含缩进的空格。Groovy开发工具包包含使用该String#stripIndent()
方法去除缩进的方法,以及使用String#stripMargin()
分隔符来识别要从字符串开头删除的文本的方法。
建立字符串时以下:
def startingAndEndingWithANewline = ''' line one line two line three '''
您会注意到结果字符串包含换行符做为第一个字符。能够经过使用反斜杠转义换行来删除该字符:
def strippedFirstNewline = '''\ line one line two line three ''' assert !strippedFirstNewline.startsWith('\n')
您可使用反斜杠字符转义单引号,以免终止字符串文字:
'an escaped single quote: \' needs a backslash'
你可使用双反斜杠来逃避转义字符自己:
'an escaped escape character: \\ needs a double backslash'
一些特殊字符也使用反斜杠做为转义字符:
逃脱序列 | 字符 |
---|---|
'\ t' |
制表 |
'\ B' |
退格 |
'\ n' |
新队 |
'\ r' |
回车 |
'\F' |
换页符 |
'\\' |
反斜线 |
'\'” |
单引号(单引号和三引号字符串) |
'\“' |
双引号(双引号和三引号双引号) |
对于键盘上不存在的字符,可使用unicode转义序列:反斜杠,后跟“u”,而后是4个十六进制数字。
例如,欧元货币符号能够表示为:
'The Euro currency symbol: \u20AC'
双引号字符串是由双引号括起来的一系列字符:
"a double quoted string"
java.lang.String 若是没有插值表达式, 双引号字符串是普通的,但若是存在插值则是groovy.lang.GString 实例。 |
要转义双引号,可使用反斜杠字符:“双引号:\”“。 |
除了单引号和三引号字符串以外,任何Groovy表达式均可以在全部字符串文字中进行插值。插值是在对字符串求值时将字符串中的占位符替换为其值的行为。占位符表达式由虚线表达式包围${}
或前缀$
。当GString被传递给经过调用toString()
该表达式将String做为参数的方法时,占位符内的表达式值将被计算为其字符串表示形式。
这里,咱们有一个字符串,其中占位符引用了一个局部变量:
def name = 'Guillaume' // a plain string def greeting = "Hello ${name}" assert greeting.toString() == 'Hello Guillaume'
可是任何Groovy表达式都是有效的,正如咱们在本例中能够看到的算术表达式:
def sum = "The sum of 2 and 3 equals ${2 + 3}" assert sum.toString() == 'The sum of 2 and 3 equals 5'
不只在${} 占位符之间容许表达式,并且语句也是如此。可是,声明的价值恰到好处null 。所以,若是在该占位符中插入了多个语句,则最后一个语句应以某种方式返回要插入的有意义值。例如,“1和2的总和等于$ {def a = 1; def b = 2; a + b}”是支持的而且按预期工做可是一个好的作法一般是坚持GString占位符中的简单表达式。 |
除了${}
占位符以外,咱们还可使用$
前缀为虚线表达式的单个符号:
def person = [name: 'Guillaume', age: 36] assert "$person.name is $person.age years old" == 'Guillaume is 36 years old'
可是,只有形式的虚线表达a.b
,a.b.c
等等,都是有效的,但会包含相似的方法调用,闭包大括号,或算术运算符括号表达式将是无效的。给定如下数字的变量定义:
def number = 3.14
如下语句将抛出一个groovy.lang.MissingPropertyException
由于Groovy认为您正在尝试访问该toString
数字的属性,该属性不存在:
shouldFail(MissingPropertyException) { println "$number.toString()" }
您能够"$number.toString()" 将解析器视为解释为"${number.toString}()" 。 |
若是你须要在GString中转义$
或${}
占位符,使它们看起来没有插值,你只须要使用\
反斜杠字符来逃避美圆符号:
assert '${name}' == "\${name}"
到目前为止,咱们已经看到咱们能够在${}
占位符内插入任意表达式,可是闭包表达式有一个特殊的状况和符号。当占位符包含箭头时${→}
,表达式其实是一个闭包表达式 - 您能够将其视为一个封闭,前面有一个美圆:
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 参数,你可使用<< leftShift运算符追加内容。在任何一种状况下,两个占位符都是嵌入式封闭。 |
从外观上看,它看起来像是一种定义要插入的表达式的更冗长的方式,可是闭包与单纯的表达式相比具备一个有趣的优点:懒惰的评估。
让咱们考虑如下示例:
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" assert lazyGString == "value == 2"
咱们定义一个number 包含的变量1 ,而后咱们在两个GStrings内插入,做为一个表达式eagerGString 和做为闭包lazyGString 。 |
|
咱们但愿结果字符串包含相同的字符串值1 eagerGString 。 |
|
一样的 lazyGString |
|
而后咱们将变量的值更改成新数字 | |
使用普通插值表达式,该值其实是在建立GString时绑定的。 | |
可是使用闭包表达式时,会在每次将GString强制转换为String时调用闭包,从而生成包含新数字值的更新字符串。 |
带有多个参数的嵌入式闭包表达式将在运行时生成异常。仅容许具备零个或一个参数的闭包。 |
当一个方法(不管是用Java仍是Groovy实现)须要a java.lang.String
,可是咱们传递一个groovy.lang.GString
实例时,toString()
会自动且透明地调用GString 的方法。
String takeString(String message) { assert message instanceof String return message } def message = "The message is ${'hello'}" assert message instanceof GString def result = takeString(message) assert result instanceof String assert result == 'The message is hello'
咱们建立一个GString变量 | |
咱们仔细检查它是GString的一个实例 | |
而后咱们将该GString传递给一个以String做为参数的方法 | |
该takeString() 方法的签名明确表示其惟一参数是String |
|
咱们还验证参数确实是String而不是GString。 |
尽管可使用插值字符串代替普通Java字符串,但它们以特定方式与字符串不一样:它们的hashCodes不一样。普通Java字符串是不可变的,而GString的结果字符串表示形式可能会有所不一样,具体取决于其内插值。即便对于相同的结果字符串,GStrings和Strings也没有相同的hashCode。
assert "one: ${1}".hashCode() != "one: 1".hashCode()
应该避免使用GString做为Map键的具备不一样hashCode值的GString和Strings,尤为是当咱们尝试使用String而不是GString检索关联值时。
def key = "a" def m = ["${key}": "letter ${key}"] assert m["a"] == null
使用初始对建立映射,其键是GString | |
当咱们尝试使用String键获取值时,咱们将找不到它,由于Strings和GString具备不一样的hashCode值 |
三重双引号字符串的行为相似于双引号字符串,另外它们是多行的,就像三重单引号字符串同样。
def name = 'Groovy' def template = """ Dear Mr ${name}, You're the winner of the lottery! Yours sincerly, Dave """ assert template.toString().contains('Groovy')
双引号和单引号都不须要在三重双引号字符串中进行转义。 |
除了一般引用的字符串以外,Groovy还提供了/
用做分隔符的字符串。Slashy字符串对于定义正则表达式和模式特别有用,由于不须要转义反斜杠。
一个slashy字符串的示例:
def fooPattern = /.*foo.*/ assert fooPattern == '.*foo.*'
只需使用反斜杠转义正斜杠:
def escapeSlash = /The character \/ is a forward slash/ assert escapeSlash == 'The character / is a forward slash'
Slashy字符串是多行的:
def multilineSlashy = /one two three/ assert multilineSlashy.contains('\n')
Slashy字符串也能够插值(即GString):
def color = 'blue' def interpolatedSlashy = /a ${color} car/ assert interpolatedSlashy == 'a blue car'
有一些问题须要注意。
空的slashy字符串不能用双正斜杠表示,由于Groovy解析器将其理解为行注释。这就是为何如下断言实际上不会编译,由于它看起来像一个非终止语句:
assert '' == //
因为slashy字符串的设计主要是为了使regexp变得更容易,因此GStrings中的一些错误就像$() slashy字符串同样。 |
美圆贬值字符串是多行GStrings,以开头$/
和结尾分隔/$
。逃脱的角色是美圆符号,它能够逃避另外一美圆或正斜线。可是美圆和正斜线都不须要被转义,除了逃避一个字符串子序列的美圆,它会像GString占位符序列同样开始,或者若是你须要转义一个序列,它会像一个结束的美圆斜线字符串分隔符同样开始。
这是一个例子:
def name = "Guillaume" def date = "April, 1st" def dollarSlashy = $/ Hello $name, today we're ${date}. $ dollar sign $$ escaped dollar sign \ backslash / forward slash $/ escaped forward slash $$$/ escaped opening dollar slashy $/$$ escaped closing dollar slashy /$ assert [ 'Guillaume', 'April, 1st', '$ dollar sign', '$ escaped dollar sign', '\\ backslash', '/ forward slash', '/ escaped forward slash', '$/ escaped opening dollar slashy', '/$ escaped closing dollar slashy' ].every { dollarSlashy.contains(it) }
字符串名称 |
字符串语法 |
内插 |
多行 |
逃避角色 |
单引号 |
|
|
||
三重单引号 |
|
|
||
双引号 |
|
|
||
三倍双引号 |
|
|
||
Slashy |
|
|
||
美圆贬值 |
|
|
与Java不一样,Groovy没有明确的字符文字。可是,您能够经过三种不一样的方式明确将Groovy字符串设置为实际字符:
char c1 = 'A' assert c1 instanceof Character def c2 = 'B' as char assert c2 instanceof Character def c3 = (char)'C' assert c3 instanceof Character
经过指定char 类型声明保存字符的变量时显式 |
|
经过与as 操做员使用类型强制 |
|
经过使用强制转换为char操做 |
当字符保存在变量中时, 第一个选项1颇有趣,而当必须将char值做为方法调用的参数传递时,其余两个(2和3)更有趣。 |
Groovy支持不一样类型的整数文字和十进制文字,由一般Number
的Java类型支持。
整数文字类型与Java中相同:
byte
char
short
int
long
java.lang.BigInteger
您可使用如下声明建立这些类型的整数:
// 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
数字也能够用二进制,八进制,十六进制和十进制数表示。
二进制数字以0b
前缀开头:
int xInt = 0b10101111 assert xInt == 175 short xShort = 0b11001001 assert xShort == 201 as short byte xByte = 0b11 assert xByte == 3 as byte long xLong = 0b101101101101 assert xLong == 2925l BigInteger xBigInteger = 0b111100100001 assert xBigInteger == 3873g int xNegativeInt = -0b10101111 assert xNegativeInt == -175
八进制数以典型格式指定,0
后跟八进制数字。
int xInt = 077 assert xInt == 63 short xShort = 011 assert xShort == 9 as short byte xByte = 032 assert xByte == 26 as byte long xLong = 0246 assert xLong == 166l BigInteger xBigInteger = 01111 assert xBigInteger == 585g int xNegativeInt = -077 assert xNegativeInt == -63
十六进制数以典型格式指定,0x
后跟十六进制数字。
int xInt = 0x77 assert xInt == 119 short xShort = 0xaa assert xShort == 170 as short byte xByte = 0x3a assert xByte == 58 as byte long xLong = 0xffff assert xLong == 65535l BigInteger xBigInteger = 0xaaaa assert xBigInteger == 43690g Double xDouble = new Double('0x1.0p0') assert xDouble == 1.0d int xNegativeInt = -0x77 assert xNegativeInt == -119
十进制文字类型与Java中的相同:
float
double
java.lang.BigDecimal
您可使用如下声明建立这些类型的十进制数:
// 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选择java.lang.BigDecimal
十进制数字类型。此外,不管float
和double
支持,但须要一个明确的类型声明,类型强制或后缀。即便BigDecimal
是十进制数的默认值,也能够在方法或闭包中接受这样的文字float
或double
做为参数类型。
十进制数不能使用二进制,八进制或十六进制表示来表示。 |
在编写长字面数字时,更难以弄清楚某些数字是如何组合在一块儿的,例如成千上万的单词组等。经过容许您在数字文字中放置下划线,更容易发现这些组:
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 |
|
长 |
|
整数 |
|
BigDecimal的 |
|
双 |
|
浮动 |
|
例子:
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
虽然稍后会介绍运算符,但讨论数学运算的行为以及它们的结果类型是很重要的。
除了分区和功率二进制操做(以下所述),
之间的二进制运算byte
,char
,short
和int
结果int
二进制运算涉及long
用byte
,char
,short
和int
致使long
二进制操做涉及BigInteger
和任何其余整数类型的结果BigInteger
涉及二进制运算BigDecimal
与byte
,char
,short
,int
并BigInteger
致使BigDecimal
之间的二进制运算float
,double
并BigDecimal
致使double
二者之间的二进制运算BigDecimal
致使BigDecimal
下表总结了这些规则:
字节 | 烧焦 | 短 | INT | 长 | 的BigInteger | 浮动 | 双 | BigDecimal的 | |
---|---|---|---|---|---|---|---|---|---|
字节 |
INT |
INT |
INT |
INT |
长 |
的BigInteger |
双 |
双 |
BigDecimal的 |
烧焦 |
INT |
INT |
INT |
长 |
的BigInteger |
双 |
双 |
BigDecimal的 |
|
短 |
INT |
INT |
长 |
的BigInteger |
双 |
双 |
BigDecimal的 |
||
INT |
INT |
长 |
的BigInteger |
双 |
双 |
BigDecimal的 |
|||
长 |
长 |
的BigInteger |
双 |
双 |
BigDecimal的 |
||||
的BigInteger |
的BigInteger |
双 |
双 |
BigDecimal的 |
|||||
浮动 |
双 |
双 |
双 |
||||||
双 |
双 |
双 |
|||||||
BigDecimal的 |
BigDecimal的 |
因为Groovy的操做符重载,一般的算术运算符与工做以及BigInteger 和BigDecimal 在Java中,不像你必须使用显式的方法对这些数字操做。 |
所述除法运算符/
(并/=
用于划分和分配)产生double
结果若是操做数是一float
或double
,和BigDecimal
不然结果(当两个操做数都是一体型的任意组合short
,char
,byte
,int
,long
, BigInteger
或BigDecimal
)。
BigDecimal
分割与所执行的divide()
,若是划分是确切的方法(即,产生了可在相同的精度和分的范围内表示的结果),或使用MathContext
与精度 最大的两个操做数的精度加上一个额外的精度的10和规模 最大的10和最大操做数规模的。
对于像Java中的整数除法,您应该使用该intdiv() 方法,由于Groovy不提供专用的整数除法运算符符号。 |
动力操做由**
操做员表示,有两个参数:基数和指数。功率操做的结果取决于其操做数和操做的结果(特别是若是结果能够表示为整数值)。
Groovy的电源操做使用如下规则来肯定结果类型:
若是指数是十进制值
若是结果能够表示为a Integer
,则返回一个Integer
不然,若是结果能够表示为a Long
,则返回aLong
不然返回一个 Double
若是指数是一个整数值
若是指数严格为负,则返回a Integer
,Long
或者Double
若是结果值适合该类型
若是指数是正数或零
若是base是a BigDecimal
,则返回BigDecimal
结果值
若是base是a BigInteger
,则返回BigInteger
结果值
若是base是a Integer
,则返回a,Integer
若是结果值适合它,不然aBigInteger
若是base是a Long
,则返回a,Long
若是结果值适合它,不然aBigInteger
咱们能够用几个例子说明这些规则:
// base and exponent are ints and the result can be represented by an Integer assert 2 ** 3 instanceof Integer // 8 assert 10 ** 9 instanceof Integer // 1_000_000_000 // the base is a long, so fit the result in a Long // (although it could have fit in an Integer) assert 5L ** 2 instanceof Long // 25 // the result can't be represented as an Integer or Long, so return a BigInteger assert 100 ** 10 instanceof BigInteger // 10e20 assert 1234 ** 123 instanceof BigInteger // 170515806212727042875... // the base is a BigDecimal and the exponent a negative int // but the result can be represented as an Integer assert 0.5 ** -2 instanceof Integer // 4 // the base is an int, and the exponent a negative float // but again, the result can be represented as an Integer assert 1 ** -0.3f instanceof Integer // 1 // the base is an int, and the exponent a negative int // but the result will be calculated as a Double // (both base and exponent are actually converted to doubles) assert 10 ** -1 instanceof Double // 0.1 // the base is a BigDecimal, and the exponent is an int, so return a BigDecimal assert 1.2 ** 10 instanceof BigDecimal // 6.1917364224 // the base is a float or double, and the exponent is an int // but the result can only be represented as a Double value assert 3.4f ** 5 instanceof Double // 454.35430372146965 assert 5.6d ** 2 instanceof Double // 31.359999999999996 // the exponent is a decimal value // and the result can only be represented as a Double value assert 7.8 ** 1.9 instanceof Double // 49.542708423868476 assert 2 ** 0.1f instanceof Double // 1.0717734636432956
Groovy使用逗号分隔的值列表(用方括号括起来)来表示列表。Groovy列表是普通的JDK java.util.List
,由于Groovy没有定义本身的集合类。java.util.ArrayList
默认状况下,定义列表文字时使用的具体列表实现,除非您决定另行指定,咱们将在后面看到。
def numbers = [1, 2, 3] assert numbers instanceof List assert numbers.size() == 3
咱们定义一个由逗号分隔的列表编号,并用方括号括起来,而后咱们将该列表分配给一个变量 | |
该列表是Java java.util.List 接口的一个实例 |
|
可使用size() 方法查询列表的大小,并显示咱们的列表包含3个元素 |
在上面的示例中,咱们使用了同类列表,但您也能够建立包含异构类型值的列表:
def heterogeneous = [1, "a", true]
这里的列表包含数字,字符串和布尔值 |
咱们提到默认状况下,列表文字其实是实例java.util.ArrayList
,可是能够为咱们的列表使用不一样的支持类型,这要归功于对as
运算符使用类型强制,或者使用变量的显式类型声明:
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
咱们使用强制as 操做符来明确请求java.util.LinkedList 实现 |
|
咱们能够说保存列表文字的变量是类型的 java.util.LinkedList |
您可使用[]
下标运算符(用于读取和设置值)访问列表元素,使用正索引或负索引来访问列表末尾的元素以及范围,并使用<<
leftShift运算符将元素附加到一个列表:
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']
访问列表的第一个元素(从零开始计数) | |
使用负索引访问列表的最后一个元素:-1是列表末尾的第一个元素 | |
使用赋值为列表的第三个元素设置新值 | |
使用<< leftShift运算符在列表的末尾追加一个元素 |
|
一次访问两个元素,返回包含这两个元素的新列表 | |
使用范围能够从列表中访问一系列值,从开始到结束元素位置 |
因为列表本质上能够是异构的,所以列表还能够包含其余列表来建立多维列表:
def multi = [[0, 1], [2, 3]] assert multi[1][0] == 2
定义数字列表列表 | |
访问最顶层列表的第二个元素,以及内部列表的第一个元素 |
Groovy重用了数组的列表表示法,可是为了制做这样的文字数组,你须要经过强制或类型声明来明确地定义数组的类型。
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
使用显式变量类型声明定义字符串数组 | |
断言咱们建立了一个字符串数组 | |
使用as 运算符建立一个int数组 |
|
断言咱们建立了一个原始int数组 |
您还能够建立多维数组:
def matrix3 = new Integer[3][3] assert matrix3.size() == 3 Integer[][] matrix2 matrix2 = [[1, 2], [3, 4]] assert matrix2 instanceof Integer[][]
您能够定义新数组的边界 | |
或者声明一个数组而不指定其边界 |
对数组元素的访问遵循与列表相同的表示法:
String[] names = ['Cédric', 'Guillaume', 'Jochen', 'Paul'] assert names[0] == 'Cédric' names[2] = 'Blackdrag' assert names[2] == 'Blackdrag'
检索数组的第一个元素 | |
将数组的第三个元素的值设置为新值 |
Groovy不支持Java的数组初始化表示法,由于花括号可能会被Groovy闭包的符号误解。 |
有时在其余语言中称为字典或关联数组,Groovy具备地图功能。映射将键与值相关联,使用冒号分隔键和值,使用逗号分隔每一个键/值对,以及用方括号括起的整个键和值。
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
咱们定义了一个字符串颜色名称的映射,与它们的十六进制编码的html颜色相关联 | |
咱们使用下标表示法来检查与red 密钥相关的内容 |
|
咱们还可使用属性表示法来断言颜色绿色的十六进制表示 | |
相似地,咱们可使用下标符号来添加新的键/值对 | |
或属性表示法,添加yellow 颜色 |
当使用键的名称时,咱们实际上在地图中定义了字符串键。 |
Groovy建立其实是实例的地图java.util.LinkedHashMap 。 |
若是您尝试访问地图中不存在的密钥:
assert colors.unknown == null
您将检索null
结果。
在上面的示例中,咱们使用了字符串键,但您也可使用其余类型的值做为键:
def numbers = [1: 'one', 2: 'two'] assert numbers[1] == 'one'
在这里,咱们使用数字做为键,由于数字能够明确地被识别为数字,所以Groovy不会像咱们以前的例子那样建立字符串键。可是考虑一下你要传递一个变量代替键的状况,让该变量的值成为关键:
def key = 'name' def person = [key: 'Guillaume'] assert !person.containsKey('name') assert person.containsKey('key')
在key 与相关的'Guillaume' 名称其实是"key" 字符串,而不是与相关联的值key 变 |
|
地图不包含'name' 密钥 |
|
相反,地图包含一个'key' 键 |
您还能够传递带引号的字符串以及键:[“name”:“Guillaume”]。若是您的密钥字符串不是有效的标识符,那么这是必需的,例如,若是您想建立一个包含哈希的字符串密钥,如:[“street-name”:“Main street”]。 |
当您须要在地图定义中将变量值做为键传递时,必须用括号括起变量或表达式:
person = [(key): 'Guillaume'] assert person.containsKey('name') assert !person.containsKey('key')
此次,咱们key 用括号括起变量,指示解析器传递变量而不是定义字符串键 |
|
地图确实包含name 密钥 |
|
可是地图不像key 之前那样包含密钥 |