Groovy
# 一、Groovy
# 1、简介
Groovy 是 用于Java虚拟机 (opens new window)的一种敏捷的动态语言 (opens new window),它是一种成熟的面向对象 (opens new window)编程语言,既可以用于面向对象编程,又可以用作纯粹的脚本语言 (opens new window)。使用该种语言不必编写过多的代码,同时又具有闭包 (opens new window)和动态语言中的其他特性。
# 2、安装
参考:http://www.groovy-lang.org/install.html
# 3、脚本对比
Aviator | Groovy | |
---|---|---|
优点 | 小巧、快速、弱类型、类自动卸载 | 1、兼容java语法、入门门槛较低; 2、 和java集成更方便,可以使用已有的java生态; |
缺点 | 1、有门槛; 2、实现复杂功能需要定制比较多的工具类 |
# 4、maven
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.4.21</version>
</dependency>
# 二、基础语法
# 1、基本类型
// 指定变量类型定义变量
int x = 10;
// 打印变量类型(注意:基础类型在Groovy里面会包装成对象类型)
println(x.class);
// 打印x的值
println x;
// 使用 def 关键字定义变量(自动推断变量类型)
def y = 10;
// 打印y变量的类型
println y.class
def q = "我是String";
// 打印q变量的类型
println q.class;
def f = 3.14;
// 打印f变量的类型
println "变量f的类型是:"+f.class
// 使用def关键字定义的变量,可以直接改变类型和值
f = "改变变量的类型";
// 打印f变量的类型
println "变量f的类型变成了:"+f.class
class java.lang.Integer
10
class java.lang.Integer
class java.lang.String
变量f的类型是:class java.math.BigDecimal
变量f的类型变成了:class java.lang.String
# 2、String
基础用法
def name1 = 'maomao'
// 打印变量name的值
println name1
println name1.class
// 使用3个单引号定义String变量(注意:它和普通String变量是有区别的,3个单引号定义String变量是有格式的)
def name3 = '''第一行
第二行
第三行'''
// 打印name3的值(注意:name3是有格式的(也就是换行也会打印出来))
println name3
def hello = "1";
// 定义变量hell2(注意:${hello}的意思就是获取hello变量的值,还有这种获取方式必须是双引号的字符串才能使用)
def hell2 = "${hello}2";
// 打印hello2的值
println hell2
println "变量hell2的类型:"+hell2.class
// ${2 + 2} 就是 2 + 2 的值(注意:mao这个变量的类型会是GString)
def mao = "hello 2 + 2 = ${2 + 2}"
println mao
// 打印调用函数后的值(注意:这个是为了测试String类型的参数可以直接传GString类型)
println echo(mao)
// 定义一个函数
String echo(String str) {
return str
}
字符串操作
def name = "maomoa"
println "变量name的长度: "+name.length()
// 将name的值扩充到10位,用a填充(如果a没传,默认空格填充)(注意:两边都会填充)
println name.center(10,"a")
// 将name的值扩充到8位,用a在左边填充填充
println name.padLeft(8,"a")
// 将name的值扩充到8位,用a在右边填充填充
println name.padRight(8,"a")
println "字符串name的值倒叙="+name.reverse()
println "字符串name的值,首字母大写="+name.capitalize()
println "判断字符串name的值是否是数字: "+name.isNumber()
println "将字符串转换为数字:"+("12".toInteger())
//--------------------------字符串比较------------------------//
def mao = 'maomoa';
// 比较字符串的大小
println name.compareTo(mao)
// name是否大于mao(注意:Groovy程序可以直接使用比较符进行比较)
println name > mao
//-------------------------获取字符串中的某个字符---------------//
println "字符串name的值的第一个字符="+name[0]
println "字符串name的值的第一到第3个字符="+name[0..2]
//-------------------------字符串的减法使用--------------------//
println "变量name的值减去oa后="+name.minus("oa")+" 注意:这个其实就是将oa替换成空串了"
def name2 = "oa";
// 直接使用减号
println "变量name的值减去oa后="+(name - name2)+" 注意:这个其实就是将oa替换成空串了"
# 3、逻辑控制
def x = 20
// switch可以匹配很多类型(具体如下)
switch (x) {
case 2.15 :
println "等于2.15"
break
case 'maomoa':
println "等于maomoa"
break
case [1,2,"3"]:
println "等于List"
break
case BigDecimal:
println "等于BigDecimal类型"
break
case 2..30:
println "在2-30的范围以内"
break
default: println "未匹配到任何值"
}
// 匹配 class
switch (x.class) {
case [Integer.class,String.class]:
println "等于Integer或String类型"
break
case BigDecimal:
println "等于BigDecimal类型"
break
default: println "未匹配到任何值"
}
// 循环0-9
for(i in 0..9){
print i+","
}
println ""
// 循环List
for(i in [1,3,5,6]) {
print i+","
}
println ""
// 循环Map
for(map in ["as":"sda","asa":"sadas","sss":1]) {
print "key="+map.key+",value="+map.value+","
}
# 4、闭包
// 定义一个没有参数的闭包
def clouser = {println "测试打印"}
// 使用call函数调用闭包
clouser.call()
// 直接使用函数的方式调用闭包
clouser()
// 定义一个使用默认参数的闭包(注意:如果闭包没有指定参数,它会有一个默认参数it)
def c2 = {println "获取默认参数it=${it}"}
c2.call()
c2.call("我是默认参数的值")
// 定义一个有参数的闭包(注意:${x} 就是获取x的值)
def c1 = {String x,String y -> println("x=${x},${y}")}
// 调用闭包
def res = c1.call("参数1","参数2")
println "闭包的返回值=${res}"
// 定义一个指定返回值的闭包
def c3 = {String c -> return "参数=${c}"}
def res1 = c3.call("11")
println "闭包的返回值=(${res1})"
// 定义一个需要传入闭包的参数
void test(Closure closure) {
// 直接调用闭包
closure.call()
}
// 执行test函数(注意:闭包参数可以写在方法的括号外)
test {
println "闭包要执行的东西"
}
// 这个写法和上面的写法等同
test() {
println "闭包要执行的东西"
}
# 三、集合操作
# 1、基本集合
package me.xu.groovy.groovy_02
// 定义一个数组(注意:如果使用了 def 关键字,那么最后一定要用 as 进行转换,否则就成了List)
String[] array1 = ["121","2312"]
def array = ["23","ss","sdfs"] as String[]
// 定义一个List(注意:List 使用 def 关键字定义)
def list = [1,3,2]
list.add(0)
// 打印List
println "list的类型="+list.class+",list的元素="+list
// 定义一个排序规则的闭包
def c = {
a,b -> a == b ? 0 : Math.abs(a) > Math.abs(b) ? 1 : -1
}
// Java方式的排序
//Collections.sort(list,c)
// Groovy方式排序(注意:这个其实就是直接调用 sort 函数,再传一个排序规则的闭包即可)
list.sort(c)
// 这个写法和上面的一样
/*list.sort() {
* a,b -> a == b ? 0 : Math.abs(a) > Math.abs(b) ? 1 : -1
}*/
// 打印List
println "list的类型="+list.class+",list的元素="+list
def list2 = ["pffs","bsf","td","qdsfsdfs"]
// 排序规则(注意:List的排序规则如果只使用一个参数,那么默认就按照返回值的大小进行排序)
list2.sort(){
str -> str.size()
}
println "List2里面的元素根据长度排序后的结果"+list2
def list3 = [1,3,4,5,6,7,7,0]
println "list3里面的最大值="+list3.max()+",list里面的最小值="+list3.min()
// 对每个元素取绝对值以后,返回最大或最小
println "list3里面的最大值="+list3.max(){m -> Math.abs(m)}+",list里面的最小值="+list3.min(){cc -> Math.abs(cc)}
// 查找List里面所有元素中第一个是偶数的元素
def v = list3.find {
val -> val % 2 == 0
}
println "第一个偶数="+v
// 查找List里面所有元素中所有是偶数的元素
def v2 = list3.findAll {
val -> val % 2 == 0
}
println "所有的偶数="+v2
// 查找元素里面是否有偶数
def v4 = list3.any{
val -> val % 2 == 0
}
println "list3里面是否包含偶数"+v4
// 其实遇到能匹配的就加1
println "list3里面有多少个偶数="+list3.count {val -> val % 2 == 0}
# 2、map
// 定义Map
def map = ["nam":"sadas","sadasda":"sda","sdad":12]
println "map的toString结果=${map}"
println "map的nam key的值="+map["nam"]
println "map的nam key的值="+map.nam
// 修改元素nam的值
map.nam = "sdadasda"
// 添加元素(注意:如果fdfdsdf键已存在,则将修改)
map.fdfdsdf = "sadasdasda"
// 添加map元素
map.sdsds = ["asa":"asdas","sada":"sadasd"]
// 注意:获取类型不能用 map.class,因为这样写是取值而不是获取Class
println "map类型="+map.getClass()+",map的元素="+map
// 定义一个HashMap(注意:如果不指定类型,默认是 LinkedHashMap)
HashMap map2 = ["asda":"sdsdfs","fgdgfd":2];
println "map2的类型="+map2.getClass()+",map2的值="+map2
// 遍历Map
map2.each {
m -> println "key=${m.key},value=${m.value}"
}
// 遍历Map(i 表示索引位置(下标))
map2.eachWithIndex {
def m, int i -> println "index=${i},key=${m.key},value=${m.value}"
}
// 遍历Map(直接遍历key和value)
map2.each {
key,value -> println "key=${key},value=${value}"
}
// 遍历Map(直接遍历key和value以及下标index)
map2.eachWithIndex {
key,value,index -> println "key=${key},value=${value},index=${index}"
}
// 查找map里面key包含as的第一个元素
def mm = map.find {
m -> m.key.indexOf("as") != -1
}
println "map里面key包含as的第一个元素=${mm}"
// 查找map里面key包含da的所有元素
def ms = map.findAll {
m -> m.key.indexOf("da") != -1
}
println "map里面key包含da的所有元素=${ms}"
// 查找map里面key包含da的所有元素的key
def ms1 = map.findAll {
m -> m.key.indexOf("da") != -1
}.collect {
m -> m.key
}
println "map里面key包含da的所有元素的key=${ms1}"
// 查找map里面key包含da的所有元素的key
def ms2 = map.findAll {
m -> m.key.indexOf("da") != -1
}.collect {
m -> m.key
}.toListString()
println "map里面key包含da的所有元素的key=${ms2}"
// 统计map里面key包含da的元素个数
def mc = map.count {
m -> m.key.indexOf("da") != -1
}
println "map里面key包含da的元素个数=${mc}"
// map以value的class类型分组
def mg = map.groupBy {
m -> m.value.getClass()
}
println "map以value的class类型分组=${mg}"
// map进行排序
def mapmap = map.sort {
m1,m2 -> m1.value.toString().size().compareTo(m2.value.toString().size())
}
println "map排序后的结果=${mapmap}"
# 四、面向对象
/**
* 定义一个接口(注意:默认public的,而且不允许定义非public的函数)
*/
interface Action {
def getA();
String getName()
}
/**
* 定义个抽象类,并实现接口(注意:默认是票public的函数也是)
*/
trait ImplAction implements Action {
// 定义一个抽象函数
abstract void aaa()
}
/**
* 注意:默认class和属性都是public的
* 人员类
*/
class Person implements Action {
String name
Integer age
Person() {}
Person(String name,Integer age) {
this.name = name
this.age = age
}
def increasAge (Integer years) {
this.age += years
}
def getA() {
this.age
}
}
// 为Person类动态添加属性(注意:如果不是在main函数里面动态添加的属性和函数就只能在当前脚本里面使用,所以建议在main函数初始化动态添加属性和函数)
Person.metaClass.sex = "sdfsdf"
// 为Person类动态添加方法(注意:如果不是在main函数里面动态添加的属性和函数就只能在当前脚本里面使用,所以建议在main函数初始化动态添加属性和函数)
Person.metaClass.UpName = {
def nae -> nae+=name+=sex
}
// 为Person类动态添加静态属性(注意:如果不是在main函数里面动态添加的属性和函数就只能在当前脚本里面使用,所以建议在main函数初始化动态添加属性和函数)
Person.metaClass.static.sesss = "44445"
// 为Person类动态添加静态方法(注意:如果不是在main函数里面动态添加的属性和函数就只能在当前脚本里面使用,所以建议在main函数初始化动态添加属性和函数)
Person.metaClass.static.UpNamesds = {
def nae -> nae+=name+=sex
}
// 创建对象
def person = new Person("maomao",1212)
println "person=${person}"
// 注意:person.name实际上调用的是setName()函数
person.name = "maomoa"
// 注意:person.name实际上调用的是getName()函数
println "person.name=${person.name}"
println "person.age=${person.age}"
println "调用动态添加的函数UpName的结果="+person.UpName("AAAAA")
# 五、JsonObject
// 定义一个List
def lists = [new Person("毛毛",23), new Person("天天",11)]
// 将对象转换为json字符串
def jsonStr = JsonOutput.toJson(lists)
println "json字符串=${jsonStr}"
println "带格式的json字符串="+JsonOutput.prettyPrint(jsonStr)
// json对象转换工具
def jsonP = new JsonSlurper()
println "将json字符串转换为对象="+jsonP.parseText(jsonStr)
# 六、Xml解析
final String xml = '''
<response version-api="2.0">
<value>
<books id="1" classification="android">
<book available="20" id="1">
<title>疯狂Android讲义</title>
<author id="1">李刚</author>
</book>
<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>
<book available="5" id="4">
<title>Android源码设计模式</title>
<author id="4">何红辉</author>
</book>
</books>
<books id="2" classification="web">
<book available="10" id="1">
<title>Vue从入门到精通</title>
<author id="4">李刚</author>
</book>
</books>
</value>
</response>
'''
// Xml解析器(注意:xml解析从父节点以下开始,不包括父节点)
def xmlP = new XmlSlurper()
def xmlObject = xmlP.parseText(xml)
// 打印xml文件里面value节点下,第0个books里面的第0个book节点下title标签的值
println xmlObject.value.books[0].book[0].title.text()
// 打印xml文件里面value节点下,第0个books里面的第0个book节点的available属性的值
println xmlObject.value.books[0].book[0].@available
// 遍历Xml里面的每一个books节点
xmlObject.value.books.each { books ->
// 遍历books下的每一book节点
books.book.each {
book -> println book.author.text()
}
}
// 查找Xml里面所有符合条件的节点
def aaa = xmlObject.depthFirst().findAll {
// 查找book节点下author值等于李刚
book -> return book.author.text() == "李刚"
}
// 这个写法和上面的等同
def bbb = xmlObject.'**'.findAll {
// 查找book节点下author值等于李刚
book -> return book.author.text() == "李刚"
}
println "查找到的Xml节点=${aaa}"
// 遍历Xml某一个节点下的所有节点(注意:这个是通过children函数)
def ccc = xmlObject.value.books.children().findAll {
// 查找节点名称等于title并且节点的ID等于2的所有节点
node -> node.name() == "title" && node.@id == "2"
// 过滤(相当于JAVA的Stream)
}.collect {
// 只要title的值
node -> node.title.text()
}
println "查找到的Xml下value节点的books节点下=${aaa}"
# 七、Java集成Groovy脚本
# 1、使用 GroovyClassLoader
GroovyCodeSource codeSource = new GroovyCodeSource(TestGroovy.class.getClassLoader().getResource("Person.groovy"));
GroovyClassLoader loader = new GroovyClassLoader();
Class aClass = loader.parseClass(codeSource);
Script instance1 = (Script) aClass.newInstance();
instance1.setProperty("name", "yaolf1");
Object result1 = instance1.invokeMethod("greet", "zhangsan1");
System.out.println(result1);
# 2、使用 GroovyShell
GroovyCodeSource codeSource = new GroovyCodeSource(TestGroovy.class.getClassLoader().getResource("a.groovy"));
GroovyShell shell = new GroovyShell();
Script instance = shell.parse(codeSource);
Object result = instance.run();
System.out.println(result);
System.out.println(instance.getClass().getName());
# 3、使用 GroovyScriptEngine
URL[] urls = List.of(TestGroovy.class.getClassLoader().getResource("")).toArray(new URL[1]);
GroovyScriptEngine engine = new GroovyScriptEngine(urls);
Class script = engine.loadScriptByName("a.groovy");
Script instance = (Script) script.newInstance();
Object result2 = instance.run();
System.out.println(result2);
# 参考
http://www.groovy-lang.org/documentation.html
https://github.sheincorp.cn/firechiang/groovy-test
上次更新: 2024/06/29, 15:13:44