Groovy 列表、数组、映射(Maps)

7. 列表

Groovy使用逗号分割列表的值,使用方括号括起,来表示列表。 Groovy列表是普通的JDKjava.util.List,因为Groovy中没有定义自己的集合类。 在默认情况下,定义列表的实现具体类是java.util.ArrayList,除非你决定自己指定,正如我们将在后面看到的。

def numbers = [1, 2, 3]         // 我们用逗号分割和方括号括起来的方法定义一个数字列表,同时我们指派这个列表到一个变量
assert numbers instanceof List  // 这个列表是Java的java.util.List接口的一个实例
assert numbers.size() == 3      // 列表的长度可以用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.LinkedListLinked
List otherLinked = [3, 4, 5]          
assert otherLinked instanceof java.util.LinkedList

我们使用as操作符强制明确要求一个java.util.LinkedList的实现

我们可以声明一个变量持有的列表是java.util.LinkedList类型的。

你可以用[]下标操作符访问列表的元素(读写值均可), 使用正数从头访问,或负数从列表的尾部访问元素,也可以使用范围, 也可以用<<左移操作符号来添加一个元素到列表:

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']

访问列表的第一个元素(由0来是算起)


用一个负数索引来访问最尾的元素:-1是从尾部算起的第一个元素


使用等号来设置一个新的值到列表的第三个元素


使用<<左移动操作符添加一个元素到列表的最后


一次访问两个元素,返回一个包含这两个元素的新列表


使用一个从开始到结束元素的位置的范围来访问列表的一个范围内的值。

如列表可以是异构性质的,列表还可以包含其他的列表来创建多维表:

def multi = [[0, 1], [2, 3]]     
assert multi[1][0] == 2

定义一个以列表作为元素的列表

访问最上面列表中的第二个元素同时是内部列表中的第一个元素的元素

8. 数组

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() == 3Integer[][] 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'

检索数组的第一元素

设置一个新值到数组的第三个元素

8.1 Java风格的数组初始化

Groovy已经支持了方括号来初始化数组值的方式,而不是使用java风格的花括号来初始化数据,这样是为了避免和闭包函数定义的方式区分开,下面是几种初始化数组的方式:

def primes = new int[] {2, 3, 5, 7, 11}
assert primes.size() == 5 && primes.sum() == 28
assert primes.class.name == '[I'

def pets = new String[] {'cat', 'dog'}
assert pets.size() == 2 && pets.sum() == 'catdog'
assert pets.class.name == '[Ljava.lang.String;'

// 传统的Groovy初始化方式也是支持的。 
String[] groovyBooks = [ 'Groovy in Action', 'Making Java Groovy' ]
assert groovyBooks.every{ it.contains('Groovy') }

9. 映射(Maps)

在其他语言中有时也被称为字典或关联数组的特性在Groovy称为映射(maps)。 映射(maps)关联键到值,用冒号来分隔键到值,用逗号分割每对键值对,同时用方括号把整个键值包起来。

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建立的maps实际上是java.util.LinkedHashMap的实例。 Groovy creates maps that are actually instances of java.util.LinkedHashMap.

如果你尝试用一个不存在的健来访问map:

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')
  • 与“Guillaume”名称关联的键实际上是“key”字符串,不是与键变量关联的值

  • 该map不包括name键

  • 该map包括key键

如果你的键值是一个不合法的标识符,那么你可以使用双引号来将键值引上,例如你想创建一个键值是这样的:["street-name": "Main street"],就可以在键值上使用双引号。

当你真的需要传入一个变量来代码键值的时候,你必须将键值使用括号括起来使用。

person = [(key): 'Guillaume']        
assert person.containsKey('name')    
assert !person.containsKey('key')
  • 这时使用括号将键值括起来,就是告诉解析器,我们传入了一个变量作为键值。

  • 这个时候,map包括name

  • 而不包含 key