注册

"Gradle"系列: 一、Gradle相关概念理解,Groovy基础(4)

五、Groovy数据结构


通过这个模块的学习,我会结合具体的例子来说明如何查阅文档来确定闭包中的参数,在讲 Map 的时候我会讲到


Groovy 常用的数据结构有如下 四种:



  • 1)、数组
  • 2)、List
  • 3)、Map
  • 4)、Range

1、数组


在 Groovy 中使用 [ ] 表示的是一个 List 集合,如果要定义 Array 数组,我们就必须强制指定为一个数组的类型

//在 Java 中,我们一般会这样去定义一个数组
String[] javaArray = ["Java", "Groovy", "Android"]

//在 Groovy 中,我们一般会使用 as 关键字定义数组
def groovyArray = ["Java", "Groovy", "Android"] as String[]

2、List


1)、列表集合定义


1、List 即列表集合,对应 Java 中的 List 接口,一般用 ArrayList 作为真正的实现类


2、定义一个列表集合的方式有点像 Java 中定义数组一样


3、集合元素可以接收任意的数据类型

//在 Groovy 中定义的集合默认就是对应于 Java 中 ArrayList 集合
def list1 = [1,2,3]
//打印 list 类型
print list1.class
//打印结果
class java.util.ArrayList

//集合元素可以接收任意的数据类型
def list2 = ['erdai666', 1, true]

那么问题来了,如果我想定义一个 LinkedList 集合,要怎么做呢?有两种方式:


1、通过 Java 的强类型方式去定义


2、通过 as 关键字来指定

//方式1:通过 Java 的强类型方式去定义
LinkedList list3 = [4, 5, 6]

//方式2:通过 as 关键字来指定
def list4 = [1, 2, 3] as LinkedList

2)、列表集合增删改查

def list = [1,2,3]
//-------------------------- 增加元素 ---------------------------------
//有以下几种方式
list.add(20)
list.leftShift(20)
list << 20

//-------------------------- 删除元素 ---------------------------------
//根据下标移除元素
list.remove(0)

//-------------------------- 修改元素 ---------------------------------
//根据下标修改元素
list[0] = 100

//-------------------------- 查询元素 ---------------------------------
//调用闭包的 find 方法,方法中接收一个闭包,闭包的参数就是 list 中的元素
list.find {
println it
}

列表集合 Api 挺多的,对于一些其他Api,使用到的时候自行查阅文档就好了,我会在下面讲 Map 的时候演示查阅 Api 文档确定闭包的参数


3、Map


1)、定义


1、Map 表示键-值表,其底层对应 Java 中的 LinkedHashMap


2、Map 变量由[:]定义,冒号左边是 key,右边是 Value。key 必须是字符串,value 可以是任何对象


3、Map 的 key 可以用 '' 或 "" 或 ''' '''包起来,也可以不用引号包起来

def map = [a: 1, 'b': true, "c" : "Groovy", '''d''' : '''ddd''']

2)、Map 常用操作


这里列举一些 Map 的常用操作,一些其他的 Api 使用到的时候自行查阅文档就好了

//---------------------------- Map 中元素访问操作 ----------------
/**
* 有如下三种方式:
* 1、map.key
* 2、map[key]
* 3、map.get(ket)
*/
println map.a
println map['b']
println map.get('c')
//打印结果
1
true
Groovy

//---------------------------- Map 中添加和修改元素 -------------------
//如果当前 key 在 map 中不存在,则添加该元素,如果存在则修改该元素
map.put('key','value')
map['key'] = "value"

3)、Map 遍历,演示查阅官方文档


现在我要去遍历 map 中的元素,但是我不知道它的 Api 是啥,那这个时候就要去查官方 Api 文档了:


http://docs.groovy-lang.org/latest/html/groovy-jdk/java/util/Map.html

fc22493a05acc451629a1ef7593c0c43.png

通过官方文档我们可以发现: each 和 eachWithIndex 的闭包参数还是不确定的,如果我们使用 each 方法,如果传递给闭包是一个参数,那么它就把 entry 作为参数,如果我们传递给闭包是两个参数,那么它就把 key 和 value 作为参数,eachWithIndex 比 each 多了个 index 下标而已.


那么我们现在就使用以下这两个 Api :

//下面为了打印输出的格式清晰,做了一些额外的操作
def map = [a: 1, 'b': true, "c" : "Groovy", '''d''' : '''ddd''']

map.each {
print "$it.key $it.value \t"
}
println()

map.each {key,value ->
print "$key $value \t"
}
println()

map.eachWithIndex {entry,index ->
print "$entry.key $entry.value $index \t"
}
println()

map.eachWithIndex { key,value,index ->
print "$key $value $index \t"
}
//打印结果
a 1 b true c Groovy d ddd
a 1 b true c Groovy d ddd
a 1 0 b true 1 c Groovy 2 d ddd 3
a 1 0 b true 1 c Groovy 2 d ddd 3

4、Range


Range 表示范围,它其实是 List 的一种拓展。其由 begin 值 + 两个点 + end 值表示。如果不想包含最后一个元素,则 begin 值 + 两个点 + < + end 表示。我们可以通过 aRange.from 与 aRange.to 来获对应的边界元素,实际操作感受一下:

//定义一个两端都是闭区间的范围
def range = 1..10
range.each {
print it + " "
}
//打印值
1 2 3 4 5 6 7 8 9 10

//如果不想包含最后一个元素
def range1 = 1..<10
range1.each {
print it + " "
}
//打印结果
1 2 3 4 5 6 7 8 9

//打印头尾边界元素
println "$range1.from $range1.to"
//打印结果
1 9

六、Groovy 文件处理


1、IO


下面我们开始来操作这个文件,为了闭包的可读性,我会在闭包上加上类型和参数:

//-------------------------------1、文件定位 --------------------------------
def file = new File('testFile.txt')

//-----------------------2、使用 eachLine Api 每次读取一行, 闭包参数是每一行的字符串------------
file.eachLine { String line ->
println line
}
//打印结果
erdai666
erdai777
erdai888

//------------------------3、获取输入流,输出流读文件和写文件---------------------------------
//获取输入流读取文件的每一行
//1
file.withInputStream { InputStream inputStream ->
inputStream.eachLine { String it ->
println it
}
}

//2
file.withReader { BufferedReader it ->
it.readLines().each { String it ->
println it
}
}

//打印结果
erdai666
erdai777
erdai888

//获取输出流将字符串写入文件 下面这两种方式写入的文件内容会把之前的内容给覆盖
//1
file.withOutputStream { OutputStream outputStream ->
outputStream.write("erdai999".getBytes())
}

//2
file.withWriter { BufferedWriter it ->
it.write('erdai999')
}

//------------------------4、通过输入输出流实现文件拷贝功能---------------------------------
//1、通过 withOutputStream withInputStream 实现文件拷贝
def targetFile = new File('testFile1.txt')
targetFile.withOutputStream { OutputStream outputStream ->
file.withInputStream { InputStream inputStream ->
outputStream << inputStream
}
}

//2、通过 withReader、withWriter 实现文件拷贝
targetFile.withWriter {BufferedWriter bufferedWriter ->
file.withReader {BufferedReader bufferedReader ->
bufferedReader.eachLine {String line ->
bufferedWriter.write(line + "\r\n")
}
}
}

2、XML 文件操作


1)、解析 XML 文件

//定义一个带格式的 xml 字符串
def xml = '''
<response>
<value>
<books id="1" classification="android">
<book available="14" id="2">
<title>第一行代码</title>
<author id="2">郭霖</author>
</book>
<book available="13" id="3">
<title>Android开发艺术探索</title>
<author id="3">任玉刚</author>
</book>
</books>
</value>
</response>
'''
//创建 XmlSlurper 类对象,解析 XML 文件主要借助 XmlSlurper 这个类
def xmlSlurper = new XmlSlurper()
//解析 mxl 返回 response 根结点对象
def response = xmlSlurper.parseText(xml)
//打印一些结果
println response.value.books[0].book[0].title.text()
println response.value.books[0].book[0].author.text()
//打印结果
第一行代码
郭霖

//1、使用迭代器解析
response.value.books.each{ books ->
books.book.each{ book ->
println book.title
println book.author
}
}
//打印结果
第一行代码
郭霖
Android开发艺术探索
任玉刚

//2、深度遍历 XML 数据
def str1 = response.depthFirst().findAll { book ->
return book.author == '郭霖'
}
println str1
//打印结果
[第一行代码郭霖]

//3、广度遍历 XML 数据
def str2 = response.value.books.children().findAll{ node ->
node.name() == 'book' && node.@id == '2'
}.collect { node ->
"$node.title $node.author"
}
println str2
//打印结果
[第一行代码 郭霖]

2)、生成 XML 文件


上面我们使用 XmlSlurper 这个类解析了 XML,现在我们借助 MarkupBuilder 来生成 XML ,代码如下:

/**
* <response>
* <value>
* <books id="1" classification="android">
* <book available="14" id="2">
* <title>第一行代码</title>
* <author id="2">郭霖</author>
* </book>
* <book available="13" id="3">
* <title>Android开发艺术探索</title>
* <author id="3">任玉刚</author>
* </book>
* </books>
* </value>
* </response>
*/
//方式1:通过下面这种方式 就可以实现上面的效果,但是这种方式有个弊端,数据都是写死的
def sw = new StringWriter()
def xmlBuilder = new MarkupBuilder(sw)
xmlBuilder.response{
value{
books(id: '1',classification: 'android'){
book(available: '14',id: '2'){
title('第一行代码')
author(id: '2' ,'郭霖')
}
book(available: '13',id: '3'){
title('Android开发艺术探索')
author(id: '3' ,'任玉刚')
}
}
}
}
println sw

//方式2:将 XML 数据对应创建相应的数据模型,就像我们解析 Json 创建相应的数据模型是一样的
//创建 XML 对应数据模型
class Response {

def value = new Value()

class Value {

def books = new Books(id: '1', classification: 'android')

class Books {
def id
def classification
def book = [new Book(available: '14', id: '2', title: '第一行代码', authorId: 2, author: '郭霖'),
new Book(available: '13', id: '3', title: 'Android开发艺术探索', authorId: 3, author: '任玉刚')]

class Book {
def available
def id
def title
def authorId
def author
}
}
}
}

//创建 response 对象
def response = new Response()
//构建 XML
xmlBuilder.response{
value{
books(id: response.value.books.id,classification: response.value.books.classification){
response.value.books.book.each{
def book1 = it
book(available: it.available,id: it.id){
title(book1.title)
author(authorId: book1.authorId,book1.author)
}
}
}
}
}
println sw

3、Json 解析


Json解析主要是通过 JsonSlurper 这个类实现的,这样我们在写插件的时候就不需要额外引入第三方的 Json 解析库了,其示例代码如下所示:

//发送请求获取服务器响应的数据
def response = getNetWorkData("https://www.wanandroid.com/banner/json")
println response.data[0].desc
println response.data[0].imagePath

def getNetWorkData(String url){
def connect = new URL(url).openConnection()
connect.setRequestMethod("GET")
//这个会阻塞线程 在Android中不能这样操作 但是在桌面程序是可以的
connect.connect()
def response = connect.content.text

//json转实体对象
def jsonSlurper = new JsonSlurper()
jsonSlurper.parseText(response)
}
//打印结果
扔物线
https://wanandroid.com/blogimgs/8a0131ac-05b7-4b6c-a8d0-f438678834ba.png

7、总结


在本篇文章中,我们主要介绍了以下几个部分:


1、一些关于 Gradle ,Groovy 的问题


2、搭建 Groovy 开发环境,创建一个 Groovy 工程


3、讲解了 Groovy 的一些基础语法


4、对闭包进行了深入的讲解


5、讲解了 Groovy 中的数据结构和常用 Api 使用,并以 Map 举例,查阅官方文档去确定 Api 的使用和闭包的参数


6、讲解了 Groovy 文件相关的处理


学习了 Groovy ,对于我们后续自定义 Gradle 插件迈出了关键的一步。其次如果你学习过 Kotlin ,你会发现,它们的语法非常的类似,因此对于后续学习 Kotlin 我们也可以快速去上手。


作者:妖孽那里逃
链接:https://www.jianshu.com/p/124effa509bb
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

1 个评论

系列文章很好,都是精髓

要回复文章请先登录注册