Syntax
This chapter covers the syntax of the Groovy programming language. The grammar of the language derives from the Java grammar, but enhances it with specific constructs for Groovy, and allows certain simplifications.
注释 在groovy中注释适合java一样的 // 为单行注释 /**/为多行注释
1. Comments
1.1. Single line comment
Single line comments start with // and can be found at any position in the line. The characters following //, till the end of the line, are considered part of the comment.
// a standalone single line comment
println "hello" // a comment till the end of the line
1.2. Multiline comment
A multiline comment starts with /* and can be found at any position in the line. The characters following /* will be considered part of the comment, including new line characters, up to the first */ closing the comment. Multiline comments can thus be put at the end of a statement, or even inside a statement.
/* 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 注释
1.3. GroovyDoc comment
类似与多行注释 groovydoc注释是多行的 但是是以/**开始 以*/结尾 你可以选择在之后的每行以一个*号开始
Similarly to multiline comments, GroovyDoc comments are multiline, but start with /** and end with */.
Lines following the first GroovyDoc comment line can optionally start with a star *. Those comments are associated with:
这些注释可以与类型定义,域和属性定义,方法定义相关联
type definitions (classes, interfaces, enums, annotations),
fields and properties definitions
methods definitions
虽然编译器不会抱怨你的注释不和上面的语言元素相匹配 但是你也要保证注释是正确的
Although the compiler will not complain about GroovyDoc comments not being associated with the above language elements,
you should prepend those constructs with the comment right before it.
/**
* 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 和 javadoc是一样的 所以java中的标记在这里同样适用
GroovyDoc follows the same conventions as Java’s own JavaDoc. So you’ll be able to use the same tags as with JavaDoc.
1.4. Shebang line
除了简单的单行注释之外 还有一个特别的单行注释 在unix系统中通常叫做shebangline 它允许脚本直接在这行命令上运行
Beside the single line comment, there is a special line comment,
often called the shebang line understood by UNIX systems which allows scripts to be run directly from the command-line,
provided you have installed the Groovy distribution and the groovy command is available on the PATH.
#!/usr/bin/env groovy
println "Hello from the shebang line"
#字符必须是文件的第一个字符 并且任何缩进都会导致编译出错
The # character must be the first character of the file. Any indentation would yield a compilation error.
2. Keywords
The following list represents all the keywords of the Groovy language:
关键字
3. Identifiers
变量名都是以字符 美元符号 或者下划线开始的 但是不能以一个数字开始
3.1. Normal identifiers
Identifiers start with a letter, a dollar or an underscore. They cannot start with a number.
一个字符是如下的范围
A letter can be in the following ranges:
'a' to 'z' (lowercase ascii letter)
'A' to 'Z' (uppercase ascii letter)
'\u00C0' to '\u00D6'
'\u00D8' to '\u00F6'
'\u00F8' to '\u00FF'
'\u0100' to '\uFFFE'
Then following characters can contain letters and numbers.
下面是一组合法的标识符
Here are a few examples of valid identifiers (here, variable names):
def name
def item3
def with_underscore
def $dollarStart
而下面是一组非法的标识符
But the following ones are invalid identifiers:
def 3tier
def a+b
def a#b
一个关键字后面跟上点也是合法的
All keywords are also valid identifiers when following a dot:
foo.as
foo.assert
foo.break
foo.case
foo.catch
3.2. Quoted identifiers
引用标识符出现在一个点后面 举个例子 persion.name 这个表达是 可以用如下的引用来表达 person."name"或者
person.'name' 特别的是 它还支持一些java中不能用作标识符的字符 像空格 短线之类的
Quoted identifiers appear after the dot of a dotted expression. For instance, the name part of the person.name expression can be quoted with person."name" or person.'name'. This is particularly interesting when certain identifiers contain illegal characters that are forbidden by the Java Language Specification, but which are allowed by Groovy when quoted. For example, characters like a dash, a space, an exclamation mark, etc.
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"
As we shall see in the following section on strings, Groovy provides different string literals. All kind of strings are actually allowed after the dot:
map.'single quote'
map."double quote"
map.'''triple single quote'''
map."""triple double quote"""
map./slashy string/
map.$/dollar slashy string/$
There’s a difference between plain character strings and Groovy’s GStrings (interpolated strings), as in that the latter case, the interpolated values are inserted in the final string for evaluating the whole identifier:
def firstname = "Homer"
map."Simson-${firstname}" = "Homer Simson"
assert map.'Simson-Homer' == "Homer Simson"
4. Strings
Text literals are represented in the form of chain of characters called strings. Groovy lets you instantiate java.lang.String objects, as well as GStrings (groovy.lang.GString) which are also called interpolated strings in other programming languages.
单引号的字符串
4.1. Single quoted string
Single quoted strings are a series of characters surrounded by single quotes:
'a single quoted string'
Single quoted strings are plain java.lang.String and don’t support interpolation.
字符串可以用+号连接
4.2. String concatenation
All the Groovy strings can be concatenated with the + operator:
assert 'ab' == 'a' + 'b'
三重单引号的字符串
4.3. Triple single quoted string
Triple single quoted strings are a series of characters surrounded by triplets of single quotes:
'''a triple single quoted string'''
三重单引号的字符串是纯的java.lang.String 并且不支持插值
三重单引号的字符串可是是多行的
Triple single quoted strings are plain java.lang.String and don’t support interpolation.
Triple single quoted strings are multiline. You can span the content of the string across line boundaries without the need to split the string in several pieces, without contatenation or newline escape characters:
def aMultilineString = '''line one
line two
line three'''
如果你的代码是缩进的,例如在一个类的方法体,你的字符串将包含缩进的空格。Groovy开发套件包含删除缩进的的字符串# stripindent()方法,并与字符串# stripmargin()方法带分隔符的识别从一个字符串的开始删除文本
If your code is indented, for example in the body of the method of a class, your string will contain the whitespace of the indentation. The Groovy Development Kit contains methods for stripping out the indentation with the String#stripIndent() method, and with the String#stripMargin() method that takes a delimiter character to identify the text to remove from the beginning of a string.
When creating a string as follows:
def startingAndEndingWithANewline = '''
line one
line two
line three
'''
你将会发现 上述的字符串是一个换行符号开始的 这可以通过一个反斜杠来删除刚刚那个换行符 如下面所示
You will notice that the resulting string contains a newline character as first character. It is possible to strip that character by escaping the newline with a backslash:
def strippedFirstNewline = '''\
line one
line two
line three
'''
assert !strippedFirstNewline.startsWith('\n')
4.3.1. Escaping special characters
转义符
You can escape single quotes with the the backslash character to avoid terminating the string literal:
'an escaped single quote: \' needs a backslash'
And you can escape the escape character itself with a double backslash:
'an escaped escape character: \\ needs a double backslash'
Some special characters also use the backslash as escape character:
unicode 转义符
4.3.2. Unicode escape sequence
For characters that are not present on your keyboard, you can use unicode escape sequences: a backslash, followed by 'u', then 4 hexadecimal digits.
For example, the Euro currency symbol can be represented with:
'The Euro currency symbol: \u20AC'
4.4. Double quoted string
Double quoted strings are a series of characters surrounded by double quotes:
"a double quoted string"
Double quoted strings are plain java.lang.String if there’s no interpolated expression, but are groovy.lang.GString instances if interpolation is present.
To escape a double quote, you can use the backslash character: "A double quote: \"".
字符串插值
4.4.1. String interpolation
任何groovy表达式可以插入任何字符串字面值 在使用插位符的地方 插值被替换 这个插位符是以${}的形式存在的 或者以$作为前缀的dotted表达式
Any Groovy expression can be interpolated in all string literals, apart from single and triple single quoted strings. Interpolation is the act of replacing a placeholder in the string with its value upon evaluation of the string. The placeholder expressions are surrounded by ${} or prefixed with $ for dotted expressions. The expression value inside the placeholder is evaluated to its string representation when the GString is passed to a method taking a String as argument by calling toString() on that expression.
Here, we have a string with a placeholder referencing a local variable:
def name = 'Guillaume' // a plain string
def greeting = "Hello ${name}"
assert greeting.toString() == 'Hello Guillaume'
But any Groovy expression is valid, as we can see in this example with an arithmetic expression:
def sum = "The sum of 2 and 3 equals ${2 + 3}"
assert sum.toString() == 'The sum of 2 and 3 equals 5
不光是表达式可以放在插位符中,声明也可以放在其中,但是这个声明不能是空的
Not only expressions are actually allowed in between the ${} placeholder. Statements are also allowed, but a statement’s value is just null. So if several statements are inserted in that placeholder, the last one should somehow return a meaningful value to be inserted. For instance, "The sum of 1 and 2 is equal to ${def a = 1; def b = 2; a + b}" is supported and works as expected but a good practice is usually to stick to simple expressions inside GString placeholders.
In addition to ${} placeholders, we can also use a lone $ sign prefixing a dotted expression:
下面展示的是在一个插位符中用一个$作为前缀的doted表达式
def person = [name: 'Guillaume', age: 36]
assert "$person.name is $person.age years old" == 'Guillaume is 36 years old'
But only dotted expressions of the form a.b, a.b.c, etc, are valid, but expressions that would contain parentheses like method calls, curly braces for closures, or arithmetic operators would be invalid. Given the following variable definition of a number:
def number = 3.14
The following statement will throw a groovy.lang.MissingPropertyException because Groovy believes you’re trying to access the toString property of that number, which doesn’t exist:
shouldFail(MissingPropertyException) {
println "$number.toString()"
}
You can think of "$number.toString()" as being interpreted by the parser as "${number.toString}()".
If you need to escape the $ or ${} placeholders in a GString so they appear as is without interpolation, you just need to use a \ backslash character to escape the dollar sign:
assert '${name}' == "\${name}"
闭包-特殊的插值
4.4.2. Special case of interpolating closure expressions
到现在位置 我们的插值都是在一个${}插位符中的 但是闭包是一个特殊的案例
当插位符是${->}时 这个表达式其实是一个闭包表达式 你可以把它想象为闭包前面有一个美元符号
So far, we’ve seen we could interpolate arbitrary expressions inside the ${} placeholder, but there is a special case and notation for closure expressions. When the placeholder contains an arrow, ${→}, the expression is actually a closure expression — you can think of it as a closure with a dollar prepended in front of it:
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参数的闭包 你可以用左移符号为它添加内容
The closure is a parameterless closure which doesn’t take arguments.
Here, the closure takes a single java.io.StringWriter argument, to which you can append content with the << leftShift operator. In either case, both placeholders are embedded closures.
表面上看来 用插值可以更加详细的定义一个表达式 但是 闭包还有一个更有趣的优点:懒惰求值
一起考虑下面的例子
In appearance, it looks like a more verbose way of defining expressions to be interpolated, but closure have an interesting advantage over mere expressions: lazy evaluation.
Let’s consider the following sample:
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“
我们定义了一个变量 是一个整型 1 并且我们通过插值将其赋给两个gstring,一个是纯表达式的eagergstring
一个是含有闭包的gstring
我们都知道最后两者的值都是相同的 然后我们改变变量number的值 对于纯表达式而言 gstring的值在一开始创建
这个gstring的时候就已经确定了 而对于闭包而言 它把qstring 强制转为string,所以新的字符串中包含了新的值也就是2 一个内嵌的闭包表达式 如果含有一个以上的参数的话 将会导致一个异常,它只允许含有0个或者1个参数
We define a number variable containing 1 that we then interpolate within two GStrings, as an expression in eagerGString and as a closure in lazyGString.
We expect the resulting string to contain the same string value of 1 for eagerGString.
Similarly for lazyGString
Then we change the value of the variable to a new number
With a plain interpolated expression, the value was actually bound at the time of creation of the GString.
But with a closure expression, the closure is called upon each coercion of the GString into String, resulting in an updated string containing the new number value.
An embedded closure expression taking more than one parameter will generate an exception at runtime. Only closures with zero or one parameters are allowed.
4.4.3. Interoperability with Java
和java 之间的交互性
当一个方法 需要一个java.lang.String的参数 而我们传递一个groovy.lang.GString的实例的时候 gstring的 toString方法将被自动调用
When a method (whether implemented in Java or Groovy) expects a java.lang.String, but we pass a groovy.lang.GString instance, the toString() method of the GString is automatically and transparently called.
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的一个实例
然后我们把它传给一个需要string作为参数的方法
takeString的签名表示它显示地要求传入一个string对象
我们也在其中确认了这个对象是string而不是gstring
We create a GString variable
We double check it’s an instance of the GString
We then pass that GString to a method taking a String as parameter
The signature of the takeString() method explicitly says its sole parameter is a String
We also verify that the parameter is indeed a String and not a GString.
gstring 和 string的哈希值
4.4.4. GString and String hashCodes
虽然插值字符串可以用来代替纯的java字符串,但是他们还是有一点地方不同的
比如 他们的哈希值就不同
纯的java字符串的哈希值是不可变得 稳定的 而gstring是变化的 它取决于插入的值
甚至对于相同结果的字符串 gstring 和 string 都含有不同的哈希值
Although interpolated strings can be used in lieu of plain Java strings, they differ with strings in a particular way: their hashCodes are different. Plain Java strings are immutable, whereas the resulting String representation of a GString can vary, depending on its interpolated values. Even for the same resulting string, GStrings and Strings don’t have the same hashCode.
assert "one: ${1}".hashCode() != "one: 1".hashCode()
gstring 和string 有不同的哈希值,所以当你用gstring来作为map的键的话 这是不妥的。我们应当使用string
GString and Strings having different hashCode values, using GString as Map keys should be avoided, especially if we try to retrieve an associated value with a String instead of a GString.
def key = "a"
def m = ["${key}": "letter ${key}"]
assert m["a"] == null
这个map的键值类型是gstring,当我们试图用string 作为键值来取值的时候,我们是找不到的,因为string和gstring含有不同的哈希值
The map is created with an initial pair whose key is a GString
When we try to fetch the value with a String key, we will not find it, as Strings and GString have different hashCode values
4.5. Triple double quoted string
Triple double quoted strings behave like double quoted strings, with the addition that they are multiline, like the triple single quoted strings.
三引号和双引号的字符行为差不多 但是三引号支持多行
def name = 'Groovy'
def template = """
Dear Mr ${name},
You're the winner of the lottery!
Yours sincerly,
Dave“”“
assert template.toString().contains('Groovy')
Neither double quotes nor single quotes need be escaped in triple double quoted strings.
4.6. Slashy string
Beyond the usual quoted strings, Groovy offers slashy strings, which use / as delimiters. Slashy strings are particularly useful for defining regular expressions and patterns, as there is no need to escape backslashes.
Example of a slashy string:
def fooPattern = /.*foo.*/
assert fooPattern == '.*foo.*'
Only forward slashes need to be escaped with a backslash:
def escapeSlash = /The character \/ is a forward slash/
assert escapeSlash == 'The character / is a forward slash'
Slashy strings are multiline:
def multilineSlashy = /one
two
three/
assert multilineSlashy.contains('\n')
Slashy strings can also be interpolated (ie. a GString):
def color = 'blue'
def interpolatedSlashy = /a ${color} car/
assert interpolatedSlashy == 'a blue car'
There are a few gotchas to be aware of.
An empty slashy string cannot be represented with a double forward slash, as it’s understood by the Groovy parser as a line comment. That’s why the following assert would actually not compile as it would look like a non-terminated statement:
assert '' == //
4.7. Dollar slashy string
Dollar slashy strings are multiline GStrings delimited with an opening $/ and and a closing /$. The escaping character is the dollar sign, and it can escape another dollar, or a forward slash. But both dollar and forward slashes don’t need to be escaped, except to escape the dollar of a string subsequence that would start like a GString placeholder sequence, or if you need to escape a sequence that would start like a closing dollar slashy string delimiter.
Here’s an example:
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 dollar slashy string delimiter
/$
assert [
'Guillaume',
'April, 1st',
'$ dollar sign',
'$ escaped dollar sign',
'\\ backslash',
'/ forward slash',
'$/ escaped forward slash',
'/$ escaped dollar slashy string delimiter'
].each { dollarSlashy.contains(it) }
4.8. String summary table
4.9. Characters
不同于java groovy显式的字符字面值,但是你可以显式的让一个groovy string 变成一个字符
可以通过下面三种方式
Unlike Java, Groovy doesn’t have an explicit character literal. However, you can be explicit about making a Groovy string an actual character, by three different means:
char c1 = 'A'
assert c1 instanceof Character
def c2 = 'B' as char
assert c2 instanceof Character
def c3 = (char)'C'
assert c3 instanceof Characte
by being explicit when declaring a variable holding the character by specifying the char type
by using type coercion with the as operator
by using a cast to char operation
The first option 1 is interesting when the character is held in a variable, while the other two (2 and 3) are more interesting when a char value must be passed as argument of a method call.
5. Numbers
Groovy supports different kinds of integral literals and decimal literals, backed by the usual Number types of Java.
5.1. Integral literals
The integral literal types are the same as in Java:
和java一样groovy有如上的整型类型
You can create integral numbers of those types with the following declarations:
你也可以用如下的方式创建数字类型
如果你用def声明一个类型 那么这个整型数字的类型可能是变化的 它取决于你给这个数字的具体类型(值的范围)
下面是声明非十进制的方法
浮点数
当写一个非常大的数字的时候 肉眼是很难确定你写了多少位的数字 所以如果让数字带下划线 那么就非常的方便
5.4数字的后缀
5.5. Math operations
这个和c++中一样 类型提升 然而并没有什么好讲的
Although operators are covered later on, it’s important to discuss the behavior of math operations and what their resulting types are.
Division and power binary operations aside (covered below),
binary operations between byte, char, short and int result in int
binary operations involving long with byte, char, short and int result in long
binary operations involving BigInteger and any other integral type result in BigInteger
binary operations between float, double and BigDecimal result in double
binary operations between two BigDecimal result in BigDecimal
The following table summarizes those rules:
Thanks Groovy’s operator overloading, the usual arithmetic operators work as well with BigInteger and BigDecimal, unlike in Java where you have to use explicit methods for operating on those numbers.
5.5.1. The case of the division operator
The division operators / (and /= for division and assignment) produce a double result if either operand is a float or double, and a BigDecimal result otherwise (when both operands are any combination of an integral type short, char, byte, int, long, BigInteger or BigDecimal).
BigDecimal division is performed with the divide() method if the division is exact (i.e. yielding a result that can be represented within the bounds of the same precision and scale), or using a MathContext with a precision of the maximum of the two operands' precision plus an extra precision of 10, and a scale of the maximum of 10 and the maximum of the operands' scale.
For integer division like in Java, you should use the intdiv() method, as Groovy doesn’t provide a dedicated integer division operator symbol.
5.5.2. The case of the power operator
6. Booleans
Boolean is a special data type that is used to represent truth values: true and false. Use this data type for simple flags that track true/false conditions.
Boolean values can be stored in variables, assigned into fields, just like any other data type:
def myBooleanVariable = true
boolean untypedBooleanVar = false
booleanField = true
true and false are the only two primitive boolean values. But more complex boolean expressions can be represented using logical operators.
In addition, Groovy has special rules (often referred to as Groovy Truth) for coercing non-boolean objects to a boolean value.
7. Lists
链表 在groovy中 list中的值用,符号隔开 然后用方括号保卫 groovy的链表是jdk中的java.util.List
groovy没有定义它自己的collection classes。
所以它都是基于java本身进行实现的
链表中可以插入任意的值
Groovy uses a comma-separated list of values, surrounded by square brackets, to denote lists. Groovy lists are plain JDK java.util.List, as Groovy doesn’t define its own collection classes. The concrete list implementation used when defining list literals are java.util.ArrayList by default, unless you decide to specify otherwise, as we shall see later on.
def numbers = [1, 2, 3]
assert numbers instanceof List
assert numbers.size() == 3
We define a list numbers delimited by commas and surrounded by square brackets, and we assign that list into a variable
The list is an instance of Java’s java.util.List interface
The size of the list can be queried with the size() method, and shows our list contains 3 elements
In the above example, we used a homogeneous list, but you can also create lists containing values of heterogeneous types:
def heterogeneous = [1, "a", true]
Our list here contains a number, a string and a boolean value
We mentioned that by default, list literals are actually instances of java.util.ArrayList, but it is possible to use a different backing type for our lists, thanks to using type coercion with the as operator, or with explicit type declaration for your variables:
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
We use coercion with the as operator to explicitly request a java.util.LinkedList implementation
We can say that the variable holding the list literal is of type java.util.LinkedList
You can access elements of the list with the [] subscript operator (both for reading and setting values) with positive indices or negative indices to access elements from the end of the list, as well as with ranges, and use the << leftShift operator to append elements to a 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']
Access the first element of the list (zero-based counting)
Access the last element of the list with a negative index: -1 is the first element from the end of the list
Use an assignment to set a new value for the third element of the list
Use the << leftShift operator to append an element at the end of the list
Access two elements at once, returning a new list containing those two elements
Use a range to access a range of values from the list, from a start to an end element position
As lists can be heterogeneous in nature, lists can also contain other lists to create multi-dimensional lists:
def multi = [[0, 1], [2, 3]]
assert multi[1][0] == 2
Define a list of list of numbers
Access the second element of the top-most list, and the first element of the inner list
8. Arrays
数组 在groovy中 数组重用了list 但是你必须定义数组的类型
Groovy reuses the list notation for arrays, but to make such literals arrays, you need to explicitely define the type of the array through coercion or type declaration.
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
Define an array of strings using explicit variable type declaration
Assert that we created an array of strings
Create an array of ints with the as operator
Assert that we created an array of primitive ints
You can also create multi-dimensional arrays:
def matrix3 = new Integer[3][3]
assert matrix3.size() == 3
Integer[][] matrix2
matrix2 = [[1, 2], [3, 4]]
assert matrix2 instanceof Integer[][]
You can define the bounds of a new array
Or declare an array without specifying its bounds
Access to elements of an array follows the same notation as for lists:
String[] names = ['Cédric', 'Guillaume', 'Jochen', 'Paul']
assert names[0] == 'Cédric'
names[2] = 'Blackdrag'
assert names[2] == 'Blackdrag'
Retrieve the first element of the array
Set the value of the third element of the array to a new value
Java’s array initializer notation is not supported by Groovy, as the curly braces can be misinterpreted with the notation of Groovy closures.
9. Maps
maps
有时候我们把它乘坐字典 或者关系数组 groovy风格的map都有一个键对应一个值 他们用:分开键和值 然后每个键值对用,分开 再以方括号包围
Sometimes called dictionaries or associative arrays in other languages, Groovy features maps. Maps associate keys to values, separating keys and values with colons, and each key/value pairs with commas, and the whole keys and values surrounded by square brackets.
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
We define a map of string color names, associated with their hexadecimal-coded html colors
We use the subscript notation to check the content associated with the red key
We can also use the property notation to assert the color green’s hexadecimal representation
Similarly, we can use the subscript notation to add a new key/value pair
Or the property notation, to add the yellow color
When using names for the keys, we actually define string keys in the map.
Groovy creates maps that are actually instances of java.util.LinkedHashMap.
If you try to access a key which is not present in the map:
assert colors.unknown == null
You will retrieve a null result.
In the examples above, we used string keys, but you can also use values of other types as keys:
def numbers = [1: 'one', 2: 'two']
assert numbers[1] == 'one'
Here, we used numbers as keys, as numbers can unambiguously be recognized as numbers, so Groovy will not create a string key like in our previous examples. But consider the case you want to pass a variable in lieu of the key, to have the value of that variable become the key:
def key = 'name'
def person = [key: 'Guillaume']
assert !person.containsKey('name')
assert person.containsKey('key')
The key associated with the 'Guillaume' name will actually be the "key" string, not the value associated with the key variable
The map doesn’t contain the 'name' key
Instead, the map contains a 'key' key
You can also pass quoted strings as well as keys: ["name": "Guillaume"]. This is mandatory if your key string isn’t a valid identifier, for example if you wanted to create a string key containing a hash like in: ["street-name": "Main street"].
When you need to pass variable values as keys in your map definitions, you must surround the variable or expression with parentheses:
person = [(key): 'Guillaume']
assert person.containsKey('name')
assert !person.containsKey('key')
This time, we surround the key variable with parentheses, to instruct the parser we are passing a variable rather than defining a string key
The map does contain the name key
But the map doesn’t contain the key key as before**重点内容**