原文链接 译文链接 译者:jackwang
groovy提供了各种类型的原生态集合支持,包括list, maps 和 ranges 。它们大多数都是基于java集合类型,同时在java集合类型中一些废弃的方法在groovy开发套件中也可以找到。
注:译者也是第一次接触groovy,由于时间和水平有限(姑且让译者使用这个理由吧,对待知识本应该一丝不苟)部分专有名词可能翻译不准确甚至有误(读者阅读的过程中最好能参考原文),恳请读者不吝留言指出,谢谢!
(译者注:原文是list literals,直译可以翻译为list字面意思,从下文内容来看指的就是list创建和获取元素,译者意译为list基本用法)
你可以使用如下方式创建一个list,注意[]是一个空list表达式。
每一个list表达式都是java.util.list的一个实现。
当然,lists也可以用于构造另外一个list:
list是一个序列集合的对象(译者注:原文是a list is an ordered collection of objects,从下文的示例代码来看,这里不是有序的意思,而是相当于java集合里的arraylist,因此认为翻译为序列比有序更为恰当):
list可以当作一个boolean值:
迭代一个list上的元素可以使用each和eachwithindex方法,示例代码如下:
除了上面的用法,通过使用迭代,还可以将某些元素转换为另外一种元素来创建一个新的集合。这也是非常有用的用法。这样的操作,通常叫做映射。在groovy里可以使用collect方法:
过滤和搜索
groovy开发套件在集合操作上提供了许多方法来拓展标准集合,一些方法示例如下:
下面是使用groovy在集合中查找最大最小值的标准代码:
除了使用闭包,你可以使用comparator来定义一个比较:
添加或删除元素
我们可以使用[]来创建一个新的空list,使用<<来追加元素在里面:
我们也可以使用下面的方法来添加元素:
特别重要的是+操作不能改变一个集合。和<<相比,它会创建一个新的list,这可能通常不是你想要的结果,同时会有性能问题。(译者注:这里和java中string类型的+操作类似)
groovy开发套件提供了下面的方法来轻松实现从集合中删除元素:
也可以使用下标操作来删除元素,这样会使原集合发生改变:
有时候你仅仅想删除第一次出现的元素,而不是删除全部匹配的元素,你可以这样是使用remove方法:
清空一个list可以使用clear方法:
set操作
groovy开发套件同样也提供了许多方法来方便进行sets操作
排序
使用collections的排序,groovy提供了许多参数来排序一个lists,从使用闭包到使用比较器,示例代码如下:
复制元素
groovy开发套件重载了一些操作来对集合进行复制操作:
在groovy里,maps(通常和arrays联系在一起)可以使用 [:] 来创建:
map的key默认是字符串类型的,[a:1]和[‘a’:1]是等效的。如果你的变量名字恰好也是a 那就会导致混乱了,可能你是想将 a 的值作为你map的key。如果是这种情况,你必须使用括号来转义,类似下面的例子:
除了map的基本操作,要得到一个map的新的拷贝,可以clone它:
上面的例子得到的就是原始map的一个投影。
maps可以像你操作bean那样通过使用属性标记来get/set map内部的元素。只要key是groovy识别的字符串:
注意:默认情况下map.foo将总是在map中搜索key为foo的元素。这意味着如果一个map钟不含有class的可以,foo.class将会返回null。如果你只是想知道类类型,你必须使用getclass() :
通常在groovy开发套件里,迭代map是用each和eachwithindex方法。maps的创建也是序列的,也就是说当你迭代一个map的时候,可以保证迭代的顺序就是添加元素的顺序:
添加一个元素到map可以使用put,批量操作可以使用putall:
删除一个map钟全部元素可以使用clear方法:
使用map基本操作生成的map使用了对象的equals和hashcode方法。这个意味着你不应该使用一个hash code经常改变的对象或者其值不可逆操作的对象放入map。
你使用一个gstring来作为map的key也是没有意义的。因为gstring的hashcode和string的hashcode并不相等。
keys,values和entries
我们可以在一个视图里查看keys,values和entries:
通过视图(也就是map的key,entry和value)返回的值来操作values是强烈不推荐的方式。因为maps操作已经有很多直接操作的方法。特别地,groovy依赖于jdk的一些方法并不保证能够安全地操作集合,比如keyset,entryset或values
groovy开发套件包含过滤,搜索集合方法,这个和list是类似的:
分组
我们可以将一个list按某些维度分组到一个map中:
ranges允许你创建一个序列值得list,它可以当成list用,因为range继承了java.util.list
ranges定义使用 .. 代表闭区间(包括起点和终点)
ranges定义使用 ..< 代表一个半开半闭,只包含第一个值不包含最后一个值。
可以看到创建一个int区间是非常高效的,可以创建一个非常轻量级的包含起点值和终点值得对象。
区间也可以用作实现了java.lang.comparable接口作为比较器的任何java对象。可以使用next()和previous()来返回netx/previous元素。举个例子,你可以创建一个string元素类型的区间:
你可以使用for循环来迭代区间元素:
当然你也可以使用更加groovy风格的方式来实现同样的效果,通过使用each方法来迭代区间元素:
区间同样可以用在switch语句中:
幸亏属性标记对lists和maps都支持,groovy 提供了非常实用的方法来使嵌套集合处理变得非常简洁,示例代码如下:
spread操作可以认为是将一个集合内联到另外一个集合。这样就可以避免使用putall方法从而将实现变得只要一行代码:
星号操作是允许你在一个集合的全部元素中调用某个方法或属性的简洁操作:
你可以使用下标来索引lists,arrays,maps。字符串类型被当成一种特殊的集合类型:
注意你可以使用区间来提取集合:
下标操作也可以用于更新已有集合(对于那些不可变集合)
值得注意的是负数也是被允许的,表示从集合后面提取元素:你可以使用负数来表示从尾开始操作list,array,string等:
同样地,如果你使用一个反向区间(起点下标大于终点下标),结果也会是反的。
对于list, maps和ranges,groovy提供了许多额外的方法来过滤,集合分组,技术等等,那些方法使集合操作更加简单,迭代操作更加容易。
特别地,我们希望你能特别地读一下groovy开发套件的api文档:
iterable额外的方法可以在这里找到
iterator额外的方法可以在这里找到
collection额外的方法可以在这里找到
list额外的方法可以在这里找到
map额外的方法可以在这里找到
configslurper是用来读配置文件的工具类,通常是grooy脚本格式的配置文件。类似于java里的*.properties文件。configslurper允许点操作符,除此之外,还允许闭包操作配置值和一些对象类型
(1)使用点操作符
(2)使用闭包来代替点操作符
从上面的例子可以看到,parse方法可以用来返回groovy.util.configobject实例,configobject是一种特别的java.util.map实现。既可以用于返回配置值,也可以返回一个不为null的新的configobject实例对象
(1)config.test还没有被实例化因此当被调用的时候将会返回一个configobject
如果点号是配置文件值的一部分,可以使用单引号或双引号将其转义。
除此之外,configslurper也支持environments . enviroments方法可以被用来处理闭包实例,它自身也有可能由好几个部分组成。假如说我们想创建一个特定的配置值来给开发环境用,当我们创建一个configslurper实例的时候我们可以使用configslurper(string)构造函数来实现特定环境的配置.
configslurper环境变量没有严格遵循任何环境变量名字。取决于特定的configslurper客户端代码。
enviroments方法是一个那只方法,但是registerconditionalblock方法可以用于注册其他方法名字,并且可以是enviroments名字。
(1)一旦一个新的块注册了,configslurper可以编码它
因为java集成原因,toproperties方法可以用于将configobject对象转换到java.util.properties对象。然后可以将其存在*.properties文本文件中。注意,在新建一个properties实例的时候配置值将会转换为string类型实例。
expando类可以用于动态创建可拓展对象。尽管它的类名没有采用expandometaclass。每一个expando对象代表一个独立的动态的实例,可以在运行时被属性或方法所拓展
一个特殊的例子是当一个动态属性注册到一个闭包代码块。一个注册就可以被方法所动态调用:
groovy提供了可观察的lists,maps和sets。每一个都是一个java.beans.propertychangeevnent事件的触发器。当元素被添加,删除,修改就会被触发。注意propertychangeevent不仅仅当某些事件发生才出发,同时可以保存新旧值。
可能会有类型改变,可观察的集合可能需要更加特别的propertychangeevnet类型。比如当添加一个元素到可观察list触发一个observablelist.elementaddedevent事件。
(1)声明一个propertychangeeventlistener可以捕捉触发事件
(2)observablelist.elementevent和它的相关类型是相对与这个监听器
(3)注册一个监听器
(4)从给定的list创建一个observablelist
(5)observablelist.elementaddedevent事件的触发器
注意,添加一个元素将会触发两个事件,第一个是observablelist.elementaddedevent 第二个是 propertychangeevent,用来通知监听器这次修改属性的size
observablelist.elementclearedevent 事件类型是另外一个有趣的事件。无论什么时候多个元素被删除,比如当我们调用clear()方法的时候,它将会保存被删除的元素
为了了解整个事件类型,建议读者阅读javadoc文档或可观察集合的源码。
这个章节里,observablemap和observableset是同一个概念,和我们见过的observablelist一样。