目录
Groovy中自带集合方法
sort方法对集合排序
findAll 查询所有符合条件的元素
collect 返回 一个新的list
inject 强大的累计功能
each、eachWithIndex
find、findIndexOf 查询符合条件的数据
any判断符合条件的数据
every查询所有条件都满足的数据
reverse将集合倒叙返回
first、last、tail查找集合中的元素
通配符 (*.)
GPath对象导航的结构
IO 操作变得更简单
.. 表示 范围
工具
ConfigSlurper配置支持工具
Expando 万能扩展类
属性变化添加监听
上一篇我们从整体学习了Groovy,从整体上了解了Groovy的概念以及特点。并且通过实践学习了Groovy的相关改变,本篇我们一起学习Groovy的开发工具包,通过相关API的学习更加深入的了解Groovy。
Groovy中自带集合方法
Groovy的集合和Java的集合是一样的,不同的是集合方法有差异,我们从集合方法开始学习。
sort方法对集合排序
sort 对集合进行排序,这个方法,可以接收1个闭包作为参数,或者无参数。
// 默认对集合进行正序排序
def lst = [13, 12, 15, 14];
def newlst = lst.sort();//默认排序
println newlst;
// 结果
[12, 13, 14, 15]
// 适用闭包作为参数自定义排序
def newlist2 = lst.sort {
a, b -> a - b ? -1 : 1
}
println newlist2;
// 结果
[15, 14, 13, 12]
findAll 查询所有符合条件的元素
findAll 返回所有符合条件的元素。它可以接收1个闭包作为参数,或者无参数。
def list = [13, 12, 15, 14,0,-1];
//[13, 12, 15, 14, -1]
println(list)
println(list.findAll())
def newlst = list.findAll();
//[13, 12, 15, 14, -1]
println newlst;
// findAll 闭包作为参数返回小于 13 的所有元素
def newlst2 = list.findAll {
value -> value < 13
};
println newlst2;
// 结果
//[12, 0, -1]
collect 返回 一个新的list
collect 返回 一个新的list,它可以接收1个闭包作为参数,或者无参数。
//- collect 返回 一个新的list,它可以接收1个闭包作为参数,或者,无参数,
def list = [13, 12, 15, 14, 0, -1];
def newlst = [];
newlst = list.collect {
it * 2
}
println newlst
// 结果
// [26, 24, 30, 28, 0, -2]
inject 强大的累计功能
inject函数具备强大的累计功能,类似JS的reduce方法。其中inject的参数可以无,也可以是个闭包。
// 以"I"方法参数设置给sum, 迭代list 将每个元素设置 elem 和 sum 拼接赋值给sum
def list = ["am", "a", "man"]
def result = list.inject("I") { sum, elem ->
"$sum $elem"
}
println result
//结果:I am a man
// 以"2"方法参数设置给p, 迭代 [1, 2, 3] 将每个元素设置 e ,计算 p * e 结果赋值给 p
def intRes = [1, 2, 3].inject(2, {
p, e -> p * e;
});
println(intRes)
// 结果:12
// 不仅仅可以遍历计算列表,实际的业务场景中,比如计算图书馆的库存。可以看到在计算库存的时候 def totalStore。若采用Java计算的话需要定义中间变量,并且需要写when判断逻辑。
class Library {
private List<BookSeries> bookSeriesList;
}
class BookSeries {
private int suitNum;
private List<Book> books;
}
class Book {
private String name;
private int store;
private double price;
}
def library = new Library(
bookSeriesList: [
new BookSeries(suitNum: 1, books: [
new Book(name: "水浒传(上)", store: 1, price: 100.00),
new Book(name: "水浒传(中)", store: 2, price: 120.00),
new Book(name: "水浒传(下)", store: 3, price: 150.00),
]),
new BookSeries(suitNum: 2, books: [
new Book(name: "三国演义(上)", store: 4, price: 100.00),
new Book(name: "三国演义(中)", store: 5, price: 120.00),
new Book(name: "三国演义(下)", store: 6, price: 150.00),
]),
new BookSeries(suitNum: 3, books: [
new Book(name: "西游记(上)", store: 7, price: 100.00),
new Book(name: "西游记(中)", store: 8, price: 120.00),
new Book(name: "西游记(下)", store: 9, price: 150.00),
]),
new BookSeries(suitNum: 4, books: [
new Book(name: "红楼梦(上)", store: 10, price: 100.00),
new Book(name: "红楼梦(中)", store: 11, price: 120.00),
new Book(name: "红楼梦(下)", store: 12, price: 150.00),
]),
new BookSeries(suitNum: 0, books: [
new Book(name: "大秦帝国(上)", store: 10, price: 100.00),
new Book(name: "大秦帝国(中)", store: 10, price: 120.00),
new Book(name: "大秦帝国(下)", store: 10, price: 150.00),
]),
]
)
when: "统计图书馆丛书总库存"
def totalStore = library.bookSeriesList.inject(0) { libraryTotalStore, bookSeries ->
libraryTotalStore + (bookSeries.suitNum > 0 ? bookSeries.books.store.sum() * bookSeries.suitNum : 0)
}
println totalStore
each、eachWithIndex
each普通迭代方法,eachWithIndex用法和each一样,唯一的不同是eachWithIndex的传入的闭包,有两个参数,第一个是值,第二个是索引。
def list = ["a", "b", "c"]
list.eachWithIndex {
String v, int index ->
println v;
println index
}
//结果:
a
0
b
1
c
2
find、findIndexOf 查询符合条件的数据
//- find 返回第一个符合条件的元素,它可以接收1个闭包作为条件参数,或者无参数。
// 没有设置参数,默认返回第一个
def list = ["a", "b", "c"]
def str = list.find();
println(str)
// 设置闭包参数,默认符合条件的那个
str = list.find({e -> e == "b"})
println(str)
// 设置闭包参数,闭包参数使用默认的关键字 it
str = list.find({it == "b"})
println(str)
//- findIndexOf 返回指定元素的索引值。它可以接收1个闭包作为条件参数。
index = list.findIndexOf({it == "b"})
println(index)
//结果:
a
b
b
1
any判断符合条件的数据
//- any 返回boolean值。只要有任意一个符合条件就返回true,它可以接收1个闭包作为条件参数,或者无参数。
def list = ["a", "b", "c"]
def result = list.any();
println(result)
result = list.any({it == "e"});
println(result)
//结果
true
false
every查询所有条件都满足的数据
//- every 返回boolean值,只有所有符合条件才返回true,它可以接收1个闭包作为条件参数,或者无参数。
def list = ["a", "b", "c"]
def result = list.every();
println(result)
result = list.every({it == "a" || it == "b" || it == "c"});
println(result)
result = list.every({it == "a"});
println(result)
result = list.every({it == "e"});
println(result)
// 结果:
true
true
false
false
reverse将集合倒叙返回
//- reverse, 它将原list倒序,返回新list。无参数
def list = ["a", "b", "c"]
list = list.reverse();
println(list)
//结果:
[c, b, a]
first、last、tail查找集合中的元素
//- first 返回原list的第一个元素,无参数
def list = ["a", "b", "c"]
def result = list.first();
println(result)
//- last 返回原list的最后一个元素,无参数
result = list.last();
println(result)
//- tail 返回一个新list,这个list包含原list(除第一个元素)的所有元素,无参数
list = list.tail();
println(list)
// 结果:
a
c
[b, c]
其它的 groupBy,tokenize, unique,max,min,count,sum 等的函数以后有时间在尝试练习。
通配符 (*.)
在Groovy中我们可以使用通配符(*.)提取我们想要的信息,就想使用Linux命令查询查看某文件类型目录时的通配符一样(ls *.txt)。我们定义一个类,实例化2个Car对象,采用通配符查询每一个实例对象中的make属性。
class Car {
String make
String model
}
def cars = [
new Car(make: 'Peugeot', model: '508'),
new Car(make: 'Renault', model: 'Clio')]
def makes = cars*.make
makes.each {
println it
}
//结果:
Peugeot
Renault
// 创建一个1到10元素的列表,并且每个元素都乘以2
def list = (1..10)*.multiply(2)
println list
// 结果:
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
// 将列表中的所有的字符串转大写
def list = ['Denver', 'Cheyenne', 'Reno', 'Sacramento']*.toUpperCase()
println(list)
// 结果:
[DENVER, CHEYENNE, RENO, SACRAMENTO]
GPath对象导航的结构
GPath是groovy代码的一个强劲对象导航的结构,名称的选择与XPath相似,XPath是一个用来描述XML(和等价物)文档的标准。正如XPath,GPath的目标是用在表达试:明确的,紧凑易读的表达式。当染改方式也被封装到Collection的GDK方法中。
// GPath 像XPath一样,可以轻松的访问多层的集合对象,如下我们定义一个 List<Map<String, Integer>> 类型,快速的获取他的某个健值对。
def listOfMaps = [['a': 11, 'b': 12], ['a': 21, 'b': 22], null]
println(listOfMaps.a);// [11, 21]
// 结果:
[11, 21]
// 我们看到最后一个元素是 null 无法获取到,但是我们使用通配符就可以
listOfMaps = [['a': 11, 'b': 12], ['a': 21, 'b': 22], null]
println(listOfMaps*.a)
// 结果:
[11, 21, null]
//采用Collection的GDK方法调用,可以看到是等价于 list*.a 的
def list = listOfMaps.collect { it?.a }
println(list)
// 结果:
[11, 21, null]
IO 操作变得更简单
// groovy可以简单明了的进行文件读写操作
//* 写入一个文件内容:
// 创建文件,并写入
new File("book.txt").text = "lly";
//* 读取一个文件内容
println new File("book.txt").text
//* 也可以通过字节方式写入
//先手动创建data文件
byte[] data = new File("data").bytes;
//把data的数据写入book2.txt
new File("book2.txt").bytes = data;
//创建 dragons.txt.txt 写入内容后,并读取dragons.txt内容
new File('dragons.txt').eachLine { line-> println(line) }
//* 如果需要用InputStream,Reader,OutputStream,Writer这些对象进行操作。groovy也提供类似的方法
//- 输入流InputStream操作
Properties properties = new Properties()
File propertiesFile = new File('/Users/liluyang/llyCode/groovy 2/src/main/resources/application.properties')
propertiesFile.withInputStream {
properties.load(it)
}
println properties.lly
println properties.yangzai
// 结果:
lly
曾经的屠龙少年
如今变成了恶龙
handsome
handsome too
//- Reader操作
def lineNo = 1
def line = 1;
new File("dragons.txt").withReader { reader ->
while ((line = reader.readLine()) != null) {
println "第${lineNo}行内容: ${line}"
lineNo++
}
}
// 结果:
第1行内容: 曾经的屠龙少年
第2行内容: 如今变成了恶龙
//- OutputStream操作
// 文件复制
def srcFile = new File("dragons.txt")
def targetFile = new File("book.txt")
targetFile.withOutputStream { outputStream ->
srcFile.withInputStream { inputStream ->
outputStream << inputStream
}
}
//- 写入Writer操作
//写入
new File('book.txt').withWriter('utf-8', {
writer -> writer.writeLine 'Hello World'
});
//精简版
new File('book.txt') << '''Into the ancient pond
A frog jumps
Water’s sound!'''
//## 极简的URLs操作
//1.数据抓取
URL url = new URL("https://www.baidu.com/");
InputStream input = (InputStream) url.getContent();
ByteArrayOutputStream out = new ByteArrayOutputStream();
int n = 0;
byte[] arr = new byte[1024];
while (-1 != (n = input.read(arr)))
out.write(arr, 0, n);
System.out.println(new String(out.toByteArray()));
.. 表示 范围
在groovy中。范围运算,可以用在循环,switch,字符串截取中。
1..10 - 包含范围的示例
1 .. <10 - 独占范围的示例
'a'..'x' - 范围也可以由字符组成
10..1 - 范围也可以按降序排列
'x'..'a' - 范围也可以由字符组成并按降序排列
// 打印 1 到 10 数字
(1..10).each { println(it)}
// 打印 1 到 100 数字
for (def i in 1..100){
println(i)
}
// 定义字符串,打印[0..4]范围字符串,打印 [0..4, 8..-1] 下标0到下表4的字符串范围,和下标为8到最后的字符串范围
def text = 'learning groovy'
println text[0..4]
println text[0..4, 8..-1]
// 结果:
learn
learn groovy
def list = ['hank', 'john', 'fred']
println list[0..1] //[hank, john]
// 打印数字 1 到小于 5 的数字
(1..<5).each { println(it) }
工具
ConfigSlurper配置支持工具
ConfigSlurper工具用于读取配置文件非常的方便,支持自定义配置文件。我们在Groovy中自定义了一段字符串,按照配置文件的格式读取它。
//- ConfigSlurper工具用于读取配置文件非常的方便
def config = new ConfigSlurper().parse('''
app.date = new Date()
app.age = 42
app {
name = "Test ${this.age}"
}
''')
def properties = config.toProperties()
println(properties."app.date")
println(properties."app.age")
println(properties."app.name")
// 结果:
Sun May 28 19:04:39 CST 2023
42
Test 42
Expando 万能扩展类
我之所以这么描述,是这个类台太强大了。Expando类是Groovy语言中的一个相当有趣的类,它的作用类似于GroovyBean类,但比GroovyBean类更加灵活。同时它还更类似于Map类,但也比Map类更加灵活。可以自定义属性和灵活赋值。
//1.
def expando = new Expando()
expando.name = { -> "abc" }
expando.say = { String s -> "${expando.name} says: ${s}" }
println expando.say('hello')
//2.
def person = new Expando()
person.name = 'Alice'
person.age = 18
person.description = {
println """
----------description---------
name: ${delegate.name}
age: ${delegate.age}
------------------------------
"""
}
person.description()
//结果:
abc says: hello
----------description---------
name: Alice
age: 18
------------------------------
属性变化添加监听
在Groovy中,可以主动监听各种集合对象变化的事件,并作自己的处理。下面以List集合为例,定义监听者ObservableList,并且绑定处理事件函数。就可以在改集合发生变化的时候调用处理函数了。
def list = new ObservableList()
def printer = { e -> println e.class }
list.addPropertyChangeListener(printer)
list.add 'Harry Potter'
list.add 'Hermione Granger'
list.remove(0)
// 结果:
class groovy.util.ObservableList$ElementAddedEvent
class java.beans.PropertyChangeEvent
class groovy.util.ObservableList$ElementAddedEvent
class java.beans.PropertyChangeEvent
class groovy.util.ObservableList$ElementRemovedEvent