一、常用的数据结构
1. 1 List
定义一个List的方式与我们平时定义的一样,有两种方式,一种是def list = new ArrayList(),另一种是def list = [1, 2, 3, 4, 5],这样定义出来的list默认也是ArrayList;而定义一个数组则是def array = [1, 2, 3, 4, 5] as int[],如果要使用Java的语法来创建数组也是一样的。
- 添加
def list = [1, 2, 3, 4, 5]
// 第一种方式:在最后添加一个元素6
list.add(6)
println list
// 第二种方式:在下标为3的位置添加元素9
list.add(3, 9)
println list
// 第三种方式(这种方式在Java中是没有的):在最后添加元素11
list<<11
println list
// 第四种方式(只针对于新对象):创建newList,并在list的基础上添加多一个10
def newList = list + 10
println newList
打印结果如下:
- 删除
def list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// 第一种方式:删除下标2的元素
list.remove(2)
println list
// 第二种方式:删除元素4
list.remove((Object) 4)
println list
// 第三种方式:删除元素5
list.removeElement(5)
println list
// 第四种方式:闭包,删除符合条件的所有
list.removeAll {
return it % 5 != 0
}
println list
打印的结果分别为:
- 查找
def list = [5, -2, 1, 4, 3]
// 查找满足条件的第一个数据
println list.find {
it % 2 == 0
}
// 查找所有满足条件的数据
println list.findAll {
it % 2 != 0
}
// 查找是否有满足条件的数据
println list.any {
it % 2 == 0
}
// 查找是否全部满足条件
println list.every {
it % 2 == 0
}
// 统计功能
println list.count {
it > 0
}
打印的结果分别为:
- 排序
def sortList = [5, -2, 1, 4, 3]
// 默认的排序规则是按照从小到大排序的
println sortList.sort()
// 按绝对值大小排序
println sortList.sort { a, b ->
a == b ? 0 : Math.abs(a) > Math.abs(b) ? 1 : -1
}
// 对象排序
def sortStringList = ['aaaaa', 'bbbb', 'c', 'ddd', 'ee']
// 按照String的size大小进行排序
println sortStringList.sort {
it.size()
}
打印结果如下:
1. 2 Map
首先我们来看一下Map的如何定义以及读取的
// Map的定义与读取
def colors = [red: 'ff0000', green: '00ff00', blue: '0000ff']
println colors['green']
println colors.green
// 看一下默认使用的数据结构是什么
println colors.getClass()
可以看到,我们在定义一个Map的时候,对于key,我们是可以不写引号的,当然如果要培养良好的习惯的话,也可以写上引号。而在读取的时候也一样,有带引号跟不带引号两种方式可以读取。
输出结果:
可以看到,以这种方式定义的Map默认使用的数据结构是LinkedHashMap
。当然,熟悉Java的也可以使用Java的方式来定义一个Map,这里不做赘述。
- 添加
def colors = ['red': 'ff0000', 'green': '00ff00', blue: '0000ff']
// 添加普通对象
colors.yellow = 'ffff00'
println colors
// 添加集合对象
colors.map = [key1: 1, key2: 2]
println colors
输出结果:
- 遍历
def students = [
1: [number: '001', name: 'youzi01'],
4: [number: '004', name: 'youzi04'],
3: [number: '003', name: 'youzi03'],
2: [number: '002', name: 'youzi02'],
6: [number: '006', name: 'youzi06'],
5: [number: '005', name: 'youzi05'],
]
// 用键值对的方式遍历
students.each { def key, def value ->
println "key = $key, value = $value"
}
// 用entry对象的方式遍历
students.each { student ->
println "key = ${student.key}, value = ${student.value}"
}
// 使用带索引的方式进行遍历
students.eachWithIndex { def student, int index ->
println "index = $index, key = ${student.key}, value = ${student.value}"
}
这里重新定义了一个Map对象,然后通过三种常见的遍历方式来测试。这里不作输出结果的展示。
- 查找
def students = [
1: [number: '001', name: 'youzi01'],
4: [number: '004', name: 'youzi04'],
3: [number: '003', name: 'youzi03'],
2: [number: '002', name: 'youzi02'],
6: [number: '006', name: 'youzi06'],
5: [number: '005', name: 'youzi02'],
]
// 查找第一个符合条件的数据
println students.find { student ->
student.value.name == 'youzi02'
}
// 查找符合条件的所有数据
println students.findAll { student ->
student.value.name == 'youzi02'
}
// 统计功能
println students.count { student ->
student.value.name == 'youzi02'
}
// 实现嵌套查询
println students.findAll { student ->
student.value.name == 'youzi02'
}.collect {
it.value.number
}
这里的查找其实与上面的List差不多,所以如果懂了List的话,Map也是很容易上手的。
输出结果如下:
- 排序
这里不对排序做示例讲解,与上面的List一样。
唯一要注意的是:Map在排序的时候会返回一个新的Map,而List是在原来的List上做排序。
1. 3 Range
Range的使用是比较简单的,下面先来看一下如何定义以及简单使用。
// 定义一个range
def range = 1..10
// 获取range的0下标
println "range的0下标:${range[0]}"
// 判断range中是否包含8
println "range中是否包含8:${range.contains(8)}"
// 获取range中的起点
println "range的起点:${range.from}"
// 获取range中的终点
println "range的终点:${range.to}"
输出结果:
我们可以点进Range的源码里查看,会发现其实Range是继承自List的
。
所以Range的增删查排序跟List是完全一样的。
二、序列化与文件操作
2. 1 json解析
- 对象转json字符串 首先定义一个简单的Person类
class Person {
String name
int age
}
然后创建一个lists,并把这个lists转换成json格式的字符串并输出。
def lists = [new Person(name: "Sherry", age: 18), new Person(name: "Miya", age: 1)]
// 第一种方式:把list转换成json格式并输出
println "第一种方式输出:"
println JsonOutput.toJson(list)
// 第二种方式:把list转换成json字符串并且格式化后再输出
println "第二种方式输出:"
println JsonOutput.prettyPrint(JsonOutput.toJson(list))
输出结果:
第一种方式输出:
[{"age":18,"name":"Sherry"},{"age":1,"name":"Miya"}]
第二种方式输出:
[ { "age": 18, "name": "Sherry" }, { "age": 1, "name": "Miya" }]
可根据上面的两种输出方式来查看对应的结果。
- json字符串转对象 接下来来看一下json字符串如何转换成对象,我们通过上面打印出的json字符串来进行测试:
def jsonSlurper = new JsonSlurper()
println jsonSlurper.parse("[{\"age\":18,\"name\":\"Sherry\"},{\"age\":1,\"name\":\"Miya\"}]".getBytes())
这个parse可以接收的数据类型是很多的,这里使用bytes来进行测试,有兴趣的可以自己看一下都支持哪些数据类型。现在来看一下输出结果:
[[age:18, name:Sherry], [age:1, name:Miya]]
可以看到输出结果对应上了上面定义的lists,可以说Groovy提供的这些转换的api很方便了。
2. 2 xml解析
- 解析xml 在Groovy中解析xml也是很简单的,下面来看个例子:
// 首先使用三引号来定义一段xml格式的文件,这样保证了该文件是以原始的格式输出的
final String xml='''
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.imiyar.groovydemo">
<test>12345</test>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".SecondActivity"/>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
'''
// 然后来定义Xml的解析对象
def xmlSlurper = new XmlSlurper()
// 这里的result拿到的只是根节点,如果要获取子节点,需要通过根节点去获取
def root = xmlSlurper.parseText(xml)
// 读取根节点的package属性
println root.@package
// 读取非命名空间的test节点
println root.test.text()
// 读取命名空间的节点
root.declareNamespace('android': 'http://schemas.android.com/apk/res/android')
// 这里需要注意的是,如果是读取命名空间的属性的话需要加单引号
println root.application.@'android:theme'
// 遍历activity节点并输出名字
root.application.activity.each { activity ->
println activity.@'android:name'
}
上面的注释已经写得很清楚了,唯一要注意的就是有些属性是需要通过declareNamespace()
先读取到命名空间,然后才可以读取得到该命名空间下的属性。
输出结果:
com.imiyar.groovydemo
12345
@style/AppTheme
.SecondActivity
.MainActivity
- 生成xml文件 假设我们要生成的xml文件是下面这样的:
<html>
<title id='123' name='android'>
<value>xml生成的</value>
</title>
<body name='java'>
<activity id='001' class='MainActivity'>abc</activity>
<activity id='002' class='SecActivity'>abc</activity>
</body>
</html>
直接上代码:
def sw = new StringWriter()
def xmlBuilder = new MarkupBuilder(sw)
xmlBuilder.html() {
title(id: '123', name: 'android') {
value('xml生成的')
}
body(name: 'java') {
activity(id: '001', class: 'MainActivity','abc')
activity(id: '002', class: 'SecActivity','abc')
}
}
println sw
总的来说,就是根据你要生成xml格式,然后分析层级关系,像上面的xml文件中,html是根节点,title跟body是html的子节点,并且title跟body是同级关系,所以需要并列写。
输出结果的结果就如上面的示例结果一模一样啦。
2. 3 文件操作
- 读文件 Groovy对于读取文件的操作还是很简单的,这里使用几个简单的例子来演示如何读取一个文件。
def file = new File("/Users/sherry/IdeaProjects/HelloWorldGroovy/HelloWorldGroovy.iml")
// 第一种读取:遍历文件
file.eachLine { line ->
println line
}
// 第二种读取:返回所有文本
println file.getText()
// 第三种读取:以List<String>返回文件的每一行
def text = file.readLines()
println text.toListString()
// 第四种读取:以java中流的方式读取文件内容
def reader = file.withReader { reader ->
// 读取文件的前100个字符
char[] buffer = new char[100]
reader.read(buffer)
return buffer
}
println reader
这里我使用的是创建Groovy项目时自动生成的一个.iml文件,现在来看一下输出结果:
第一种读取跟第二种读取方式返回的结果一样:
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="groovy-3.0.9" level="application" />
</component>
</module>
第三种读取结果(以List的形式输出):
[<?xml version="1.0" encoding="UTF-8"?>, <module type="JAVA_MODULE" version="4">, <component name="NewModuleRootManager" inherit-compiler-output="true">, <exclude-output />, <content url="file://$MODULE_DIR$">, <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />, </content>, <orderEntry type="inheritedJdk" />, <orderEntry type="sourceFolder" forTests="false" />, <orderEntry type="library" name="groovy-3.0.9" level="application" />, </component>, </module>]
第四种读取结果(读取前100个字符):
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="Ne
- 写文件 写入文件也相对简单,这里只写两个简单的例子。
def file = new File("/Users/sherry/IdeaProjects/HelloWorldGroovy/HelloWorldGroovy.iml")
// 在原有的文件后面拼接数据
file.append('123456789')
// 覆盖原本的文件内容
file.withWriter('utf-8') {
writer.writeLine '123'
writer.writeLine '456'
writer.writeLine '789'
}
注释很清晰易懂,所以这里就不作输出结果的展示了,大家可以自己尝试一下。