Gradle学习笔记之Groovy简单使用
创始人
2024-03-18 00:03:55
0

简介

groovy可以当成java的脚本化改良版,同样运行于JVM之上,可以很好地和java代码及相关库进行交互,既可以面向对象编程,也可以用作纯粹的脚本语言。Groovy支持动态类型转换、闭包、元编程、函数式编程、默认作用域为public(不支持default)、基本类型为对象(可以直接调用对象的方法)、支持领域特定语言DSL和其他简洁语法,并且完全兼容java语法。

官方文档,下载地址,下载好压缩包后,解压、将bin目录的路径加入到path环境变量中即可,而后在命令行中验证:

C:\Users\songzeceng>groovy -v
Groovy Version: 4.0.2 JVM: 1.8.0_231 Vendor: Oracle Corporation OS: Windows 10

在Idea中创建groovy项目

创建新项目时,选择Groovy,然后在Groovy library中选择groovy解压目录(已有Groovy library则不用),再点击Next:
在这里插入图片描述
而后给项目起个名字,点击Finish:
在这里插入图片描述
最后,会得到如下所示的groovy项目:
在这里插入图片描述

Groovy基本语法

可参见官方文档
在这里插入图片描述

类的定义

class Test {int a = 1String nameboolean flag
}

Groovy脚本:

def username = 'szc'println(username)

编译后,Groovy类产生的字节码,反编译成java代码后,内容如下:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import groovy.transform.Generated;
import groovy.transform.Internal;
import java.beans.Transient;public class Test implements GroovyObject {private int a;private String name;private boolean flag;@Generatedpublic Test() {byte var1 = 1;this.a = var1;MetaClass var2 = this.$getStaticMetaClass();this.metaClass = var2;}@Generated@Internal@Transientpublic MetaClass getMetaClass() {MetaClass var10000 = this.metaClass;if (var10000 != null) {return var10000;} else {this.metaClass = this.$getStaticMetaClass();return this.metaClass;}}@Generated@Internalpublic void setMetaClass(MetaClass var1) {this.metaClass = var1;}@Generatedpublic int getA() {return this.a;}@Generatedpublic void setA(int var1) {this.a = var1;}@Generatedpublic String getName() {return this.name;}@Generatedpublic void setName(String var1) {this.name = var1;}@Generatedpublic boolean getFlag() {return this.flag;}@Generatedpublic boolean isFlag() {return this.flag;}@Generatedpublic void setFlag(boolean var1) {this.flag = var1;}
}

反编译分析

Groovy脚本得到的反编译java代码如下:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//import groovy.lang.Binding;
import groovy.lang.Script;
import org.codehaus.groovy.runtime.InvokerHelper;public class Demo01 extends Script {public Demo01() {}public Demo01(Binding context) {super(context);}public static void main(String... args) {InvokerHelper.class.invoke(InvokerHelper.class, Demo01.class, args);}public Object run() {Object username = "szc";return this.invoke(this, username);}
}

可见两者的父类是不同的。我们可以在Groovy脚本中定义类,但类名不能和文件名一致:

def username = 'szc'println(username)class Person {int ageString name
}//class Demo01 { // 类名不能和文件名一致
//    
//}

实际上,更推荐用def定义变量、字段或方法:

def count = 1class Person {def agedef namepublic def getName() {return name}
}

类的使用

def p = new Person(hometown: "Anyang") // 字段赋值方式1:具名构造器
p.age = 25 // 字段赋值方式2:对象.字段名 = 字段值
p["name"] = "szc" // 字段赋值方式3:对象["字段名"] = 字段值
p.setGender("male") // 字段赋值方式4:对象.set字段名(字段值)println p.metaClass.class.name // 不引起歧义的情况下,方法调用的()可以省略
println p.toString()
println p.getName()
println p.say()class Person {def agedef namedef genderdef hometownpublic def getName() {return name}public def say() {"${name} said, 'Oh my Jesus!'" // 方法体最后一句,即为方法返回值}@Overridepublic String toString() {return "Person{" +"age=" + age +", name=" + name +", gender=" + gender +", hometown=" + hometown +'}';}
}

引号和字符串:

def s = "test"
def s1 = '单引号字符串,不支持换行操作和$引用,$(s)'
def s2 = "双引号字符串,不支持换行操作,但支持\$引用,${s}"
def s3 = """

三双引号字符串,支持换行操作,支持$引用:

${s}
"""
def s4 = '''三但引号字符串,支持换行操作,但不支持\\$引用:${s}
'''
println s1
println s2
println s3
println s4/*
单引号字符串,不支持换行操作和$引用,$(s)
双引号字符串,不支持换行操作,但支持$引用,test三双引号字符串,支持换行操作,支持$引用:
test三但引号字符串,支持换行操作,但不支持\$引用:
${s}
*/

输出一下四种字符串的类型:

println s1.class.name // java.lang.String
println s2.class.name // org.codehaus.groovy.runtime.GStringImpl
println s3.class.name // org.codehaus.groovy.runtime.GStringImpl
println s4.class.name // java.lang.String

可见,单引号字符串类型就是String,双引号字符串的类型则是GStringImpl

列表

Groovy中的列表就是ArrayList,但是支持+、-、+=、-=这些操作符,以便向列表里添加或删除新的列表,遍历时,支持以闭包的形式遍历:

def list1 = [1, 2, 3, 4, 5]
println(list1) // [1, 2, 3, 4, 5]
list1.add(6)
println(list1) // [1, 2, 3, 4, 5, 6]
list1 = list1.plus([7, 8, 9, 10])
list1 += [11, 12, 13, 14]
println(list1) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]list1.remove(list1.size() - 1)
list1 = list1 - [11, 12]
list1.removeAll([11, 10])
println(list1) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 13]
println(list1.pop()) // 弹出第一个元素,输出为1
println(list1) // [2, 3, 4, 5, 6, 7, 8, 9, 13]
list1.putAt(15, 20) // 给指定位置设置元素值,不必和已有数据连续
list1[18] = 92 // 给指定位置设置元素值的另一种方式
println(list1) // [2, 3, 4, 5, 6, 7, 8, 9, 13, null, null, null, null, null, null, 20, null, null, 92]// 遍历列表
list1.each {if (it instanceof Integer && it != null) { // it即当前元素def x = it * 2println(x)} else {println(0)}
}
// 输出:
/*
4
6
8
10
12
14
16
18
26
0
0
0
0
0
0
40
0
0
184
*/

映射

Groovy中的映射是LinkedHashMap,同样支持+、-、+=、-=这些操作符,遍历时,支持以闭包的形式遍历:

def map = ["Name": "szc", "Age": 25] // 映射初始化
map.put("Gender", "male") // 往映射里添加键值对,键已存在则覆盖
map += ["Hometown": "Anyang", "School": "UESTC"] // 往映射里添加新的映射,通过操作符的方式
println(map) // [Name:szc, Age:25, Gender:male, Hometown:Anyang, School:UESTC]map.remove("School") // 从映射里删除键对应的键值对,无此键则跳过
map.remove("Hometown", "Anyang") // // 从映射里删除键和值对应的键值对,无此键值对则跳过
map = map - ["Gender": "male"] // 从映射里删除子集映射,通过操作符的方式
println(map) // [Name:szc, Age:25]// 遍历映射,以键值对的方式
map.each {key, value -> {println("key: $key, value: $value")
}}// 输出:
/*
key: Name, value: szc
key: Age, value: 25
*/// 遍历映射,以entry的方式
map.each {println("key: ${it.key}, value: ${it.value}")
}
// 输出:
/*
key: Name, value: szc
key: Age, value: 25
*/

类导入和异常处理

跟java中类似:

// 类导入
import groovy.xml.MarkupBuilderdef builder = new MarkupBuilder()// 异常捕获方式1:和java里完全一样
try {def x = 1, y = 0def t = x / y
} catch (e) {e.printStackTrace()
} finally {println ("here we are at finally")
}// 异常捕获方式2:try-catch中嵌套try-finally,和方式一等效
try {try {def x = 1, y = 2def t = x / yprintln(t)} finally {println ("here we are at finally")}
} catch (e) {e.printStackTrace()
}

闭包

定义

闭包是一个开放的匿名代码块,可以有参数(默认为it)和返回值,可以引用周围作用域中声明的变量,语法:

{
[params ->] statements
}

调用

先将闭包赋值给一个变量,再通过变量名()或变量名.call()调用:

def name = "test"def f1 = {Integer x, Integer y, Integer z -> {println("$name, x = $x, y = $y, z = $z")Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2))
}}def ret = f1(1, 2, 5)
println(ret)
println f1.call(2, 3, 4)// 输出:
/*
test, x = 1, y = 2, z = 5
5.477225575051661
test, x = 2, y = 3, z = 4
5.385164807134504
*/

实际开发中,经常把闭包当成一个对象,传入给方法:

// 无参闭包做参数
def run(Closure closure) {println("Start running.......")closure() // 执行闭包println("Stop running.......")
}run { // 传入无参闭包println("Running....")// -> println("Running....") 也可以这样指定无参闭包,上面的方式带有隐式参数it
}// 有参闭包做参数
def distance(Closure closure, int x1, int x2, int y1, int y2) {closure(x1, x2, y1, y2)
}// 传入有参闭包和参数,得到返回结果并输出
def ret1 = distance({ int x1, int x2, int y1, int y2 ->{Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2))}
}, 8, -2, 4, 9)println(ret1)// 输出:
/*
Start running.......
Running....
Stop running.......
11.180339887498949
*/

如果方法中的有参闭包参数是参数列表的最后一个,那么调用该方法时,可以将有参闭包写在方法调用外面:

def distance2(int x1, int x2, int y1, int y2, Closure closure) { // 有参闭包为方法的最后一个参数closure(x1, x2, y1, y2)
}println(distance2(8, -2, 4, 9) { // 将有参闭包体写在方法调用外面int x1, int x2, int y1, int y2 ->{Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2))}
})

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWR报告解读 WORKLOAD REPOSITORY PDB report (PDB snapshots) AW...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
群晖外网访问终极解决方法:IP... 写在前面的话 受够了群晖的quickconnet的小水管了,急需一个新的解决方法&#x...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
Azure构建流程(Power... 这可能是由于配置错误导致的问题。请检查构建流程任务中的“发布构建制品”步骤,确保正确配置了“Arti...