0、安装Groovy
1、解压并配置环境变量
GROOVY_HOME=F:\project\Groovy
2、输入groovy -v
查看版本信息
1、了解前提
1.1、什么是Groovy?
Groovy是机遇Java虚拟机的一种敏捷的动态语言,它是一种成熟的OOP(面向对象)编程语言,既可以用于面向对象编程,又可以用作纯粹的脚本语言。使用该种语言不必编写过多的代码,同时又具有闭包和动态语言的其他特性。
1.2、于Java相比,Groovy的不同点或优势
1、Groovy完全兼容Java语法,可以做脚本也可以做类
2、分号是可选的,一般不会写,都是使用换行作为结束
3、类、方法、字段都是公开的,没有访问权限限制
4、默认生成具名(名值对)参数构造器 key: value
5、字段不定于访问权限时,编译器自动给字段添加 getter/setter方法
6、字段可以使用点来获取,无访问权限的也可使用getter/setter操作
7、方法可以省略return关键字,自动检索最后一行最为返回值。
8、空值比较不会出现空指针异常。
1.3、Groovy的高级特性
1、assert断言:可以用assert代替之前的Java的断言语句。
2、可选类型:可使用类JavaScript的弱类型,可使用def来表示任意类型。
3、方法调用:调用带参数的方法可以省略括号
4、字符串定义:字符串定义有三种方式,单引号,双引号和三引号
5、集合API:Groovy有自己的API也兼容Java的API
6、闭包:Groovy的一大特性,跟方法类似的代码块,他可以作为一个变量的值,也可以是一个参数传递给一个方法。
{
// 这样就是一个闭包
}
2、学习路线
2.1、数据语法
2.1.1、list类型
/**
* 添加数据
*/
list = []
// 添加数据
list.push(123)
list << ("123we")
//如果想要强制添加某一个数据需要加上 as 来指定类型
list << (1 as Integer)
list << ("123" as String)
/**
* 遍历数据
*/
for (int i = 0; i < 10; i++) {
println(list[i])
}
for (iten in list) {
println("你好")
println(iten)
}
list.stream().forEach((item) -> {
println(item)
})
list.each {
println(it)
}
2.1.2、map
// 定义
def map = [a: 2, b: new Date()]
// 写入
map.put('aaa', 'bbbbb')
// 写入
map.a = 23 as Integer
//println(map)
//println(map.a)
println("----------------------")
2.1.3、在Groovy中任何数据都是对象
// 循环100次
100.times { println(it) }
a = " 123 ".trim()
println(a)
a = true.compareTo(true)
println(a)
2.1.4、类的属性操作更简单
class JavaBean {
String a;
}
def bean = new JavaBean()
def a = bean.a
println(a)
2.1.5、格式化输出字符串
aa = 10
bb = 1
xx = "我是aa,我的值:${aa};我是bb,我的值:$bb"
println(xx)
2.1.6、switch
def x = new JavaBean()
switch (x) {
case [1, 2, 3, 4]:
println("当数据为1,2,3,4中一个数据时就可以走这里")
break
case 10..10000:
println("这里的10..10000表示从10到10000的闭区间所有的整数")
break
case Date:
println("这里表示x是一个时间")
break
case JavaBean:
println("这里表示是一个JavaBean对象")
break
default:
println("都不走走这里")
}
2.1.7、闭包下的默认变量
/**闭包*/
/**
* it:当闭包方法中,没有定义任何参数时,也可以直接用it遍历
* */
println("----------it-----------")
list = [1, 2, 3, 4, 5, 6]
list.each { println(it) }
/**
* this+owner:基本跟this一样,处理一种情况:如果该闭包是在其他的闭包中定义的,那么owner就是只想定义它的闭包对象
* */
println("----------this+owner-----------")
def xx = {
println("xx的:" + this)
println("xx的:" + owner)
def aa = {
println("aa的:" + this)
println("aa的:" + owner)
}
aa.call()
}
xx.call()
/**
* delegate
* */
println("----------delegate-----------")
def myDelegate = {
println(this)
println(owner)
println(delegate)
}
myDelegate.call()
println("----------执行setDelegate-----------")
myDelegate.setDelegate("abc")
myDelegate.call()
2.1.8、元编程
在Groovy中,可以使用metaClass
类来对元数据添加属性和方法
如String类,添加一个uppers方法
aa = "wdwd"
String.metaClass.toUpper = {
-> toUpperCase();
}
def upper = aa.toUpper()
println(upper)
String.metaClass.to = {
-> toString()
}
def to = "2".to()
println(to)
2.1.9、强数据类型检查
@TypeChecked
class Type {
// Integer a = 1.0 这里会报错:Cannot assign 'BigDecimal' to 'Integer'
}
list = [1, 2, 3, 4]
list.push(2 as Integer) // 通过as检查2是不是Integer数据类型
2.1.10、三目运算
/**
* 三目运算
* */
a = true
san = a ?: "当a为空或者为false是走这里"
2.1.11、安全访问
/**
* 安全访问
* */
class Person {
String age;
}
Person person = new Person()
def age = person?.age
println(age)
2.2、Groovy自带工具
-
使用
groovyConsole groovy
可以启动groovy
的自带的idea. -
groovyc
:自带的变异工具,使用他可以拿到编译后的java
文件. -
使用
groovysh
可以打开shell可以编写groovy. -
groovydoc
:文件生成工具
2.3、GDK
2.3.1、自带的集合方法
1、排序
1.1、sort
sort:对集合进行排序,这个方法,可以接受一个闭包参数,或者无参。
/**
* 排序
* */
list = [23, 41, 421, 23, 12, 3]
def sortInc = list.sort() // 默认为升序排序
println("排序后:" + sortInc)
// 自定义排序
println("----------自定义排序---------------")
def newList = list.sort({
a, b -> a - b ? -1 : 1
})
println(newList)
b = -10
c = 1
a = b - c ? -1 : 1 // 只有b和c的值都相等时做减法a的值才为1,其余都为-1
println(a)
1.2、reverse
reverse:将原list倒序,返回一个新的list
2、find
2.1、findAll
findAll:返回符合条件的元素,他可以接收一个闭包参数或者无参。
/**
* findAll
* */
def listAll = list.findAll()
println(listAll)
def gl10All = list.findAll({
a -> a > 100
})
println(gl10All)
def all = list.findAll({
item ->
{
return item == 10;
}
})
println(all)
2.2、find
list = [1, 1, 1, 1, 1]
def find = list.find({
item ->
{
item == 1
}
})
find:作用和findAll类似,但是find只会返回第一个符合条件的
2.3、findIndexOf
findIndexOf:返回满足条件的第一个元素的下标值。
3、返回新list
3.1、collect
collect:返回一个新的list,他可以接受一个闭包参数或者无参。
println("--------------collect---------------")
def collect = list.collect()
println(collect)
def doCollect = list.collect({
println("每一个it为:" + it)
if (it == 10) {
return it * it
}
return it - 1;
})
println(doCollect)
3.2、tail
tail:返回一个新的list,它包含list中的所有的元素(除了第一个元素)
4、inject
inject:一个累积的过程方法(有点像js的reduce),传入inject方法中的ini作为sum的初始值,在遍历collection的过程中,讲处理结果(“$sum $elem”)保存到sum中。
list = ["love", "hello"]
/**
* "$elem $sum"可以理解为字符串的拼接,$sum作为起始值还是作为做后的值只需看他在$elem的前面还是后面
* 如果$sum在后面说明每一次拼接新的元素都在最前面
* 如果$sum在前面说明每一次拼接新的元素都在最后面
* */
def aa = list.inject("ini") {
sum, elem -> "$elem $sum"
}
println(aa)
5、each
和eachWithIndex
- each:普通的迭代遍历
eachWithIndex
:他的作用和each一样,但是他要传入一个闭包,有两个参数,一个是值,一个是索引。
list = [1233213, 312, 31, 23, 12, 31, 23, 12, 3, 123, 1, 24, 12, 4, 2435, 34, 5]
list.each({
it -> println(it)
})
list.eachWithIndex { int entry, int i ->
{
println(entry + "--------------" + i)
}
}
6、every
every:接收一个闭包,返回为一个布尔值,当所有条件都满足时才返回true
def every = list.every(item -> {
item > 0
})
println(every)
7、any
any:和every的使用相同,只不过any的条件中只要有一个为真那么就返回真。
8、first
first:返回list的第一个元素
def first = list.first()
println(first)
9、last
last:返回list的最后一个元素
println(list.last())
println(list.lastIndexOf(10))
// 在原数组删除最后一个元素,返回为被删除的数据
def last = list.removeLast()
println(list)
println(last)
// 删除数组中最大的元素
def last1 = list.sort().removeLast()
println(last1)
10、groupBy、unique、max、min、count、sum等
def max = list.max()
println(max)
println(list.min())
println(list.unique())
println(list.sum())
2.3.2、通配符
*:可以很方便的访问集合对象所有的属性
@TypeChecked
class Car {
String make
String model
}
def cars = [
new Car(make: UUID.randomUUID().toString(), model: UUID.randomUUID().toString()),
new Car(make: UUID.randomUUID().toString(), model: UUID.randomUUID().toString())
]
def car_model = cars*.model
car_model.each {
println(it)
}
def numbers = 2..10.multiply(2) // Number:https://blog.csdn.net/u011422561/article/details/91353477
println(numbers)
def upperCase = ["driver", "sky"]*.toUpperCase()
println(upperCase)
2.3.3、GPath
像Xpath语法一样可以轻松访问多层的集合对象。
a = [
["a": 123],
["a": 1],
["a": 12]
]
println(a.a.max())
2.3.4、IO操作
1、普通文件操作
// 创建文件并读取内容
def file = new File('./1.txt').text
println(file)
// 如果没有当前文件就创建文件
def file1 = new File("./file.txt")
// 将内容写入文件
//file1.text = "123213dawd"
String fileName = './file.txt'
// 通过字节的形式操作文件
def file2 = new File(fileName).bytes
println(file2)
// 读取文件内容,然后一行一行的输出
new File(fileName).eachLine { line ->
println(line)
}
2、InputStream操作
// 通过流的形式读取
def propertiesFile = new File('./test.properties') // 内容为:name=re
Properties properties = new Properties();
propertiesFile.withInputStream {
properties1.load(it)
}
def name = properties.name
println(name)
3、Reader操作
// 通过Reader进行文件的读取操作
def lineNo = 1
def line = 1;
new File(fileName).withReader {
reader ->
{
while ((line = reader.readLine() != null)) {
println("第${lineNo}行内容:${line} ----- ${reader.readLine()}")
lineNo++;
}
}
}
4、Writer操作
基本操作
new File('./dwd.txt').withWriter('utf-8', {
writer -> writer.writeLine('hello world')
})
精简版本
// Writer的精简版本
new File('精简版本.txt') << '''
这是一个精简版本的文件
new File('精简版本')
'''
5、操作Url
// Url操作
def text = "http://ww.baidu.com".toURL().text
println(text)
6、Ranges 用 … 表示范围
返回
// 操作返回
println((1..10)*.multiply(2))
println((10..1)*.multiply(2))
('a'..'z').each { println(it) }
截取
text = "hello world"
println(text[0..2])
(1..<6).each { println(it) }
2.3.5、工具
1、ConfigSlurper
ConfigSlurper
工具可以对读取配置文件十分方便
def config = new ConfigSlurper().parse(
'''
app.data=new Date()
'''
)
def pp = config.toProperties()
println(pp."app.data")
2、Expando
Expando
类是Groovy语言的一个相当有趣的类
他的作用类似于GroovyBean类,但是比他更灵活,同时他还类似于Map类,但也比Map更加灵活。
def expando = new Expando();
expando.name = { -> "abc" }
expando.say = {
String s -> "${expando.name} say ${s}"
}
def say = expando.say("hello")
println(say)
def person = new Expando();
person.name = "zhangsan"
person.age = 18
person.des = {
println("""
-----------description-----------
""")
}
person.des()
3、添加监听
def list = new ObservableList()
def printer = {
e -> println(e.class)
}
list.addPropertyChangeListener(printer)
list.add('hello world1')
list.add('hello world2')
list.add('hello world3')
list.remove(0)
2.4、Java新特性
2.4.1、参数默认值
可以对定义的方法参数设置默认值
def func(args = "abc"){
println(args);
}
2.4.2、注解
-
使用
@ToString
可以帮助用户提供运行时的数据信息。 -
使用
@EqualsAndHashCode
注解可以使equals相等的两个对象的hashCode
也相等 -
使用
@TupleConstructor
注解可以在传javaBean
的数据时,免去传key,直接传value -
@Canonical
注解时以上三个注解的合体。
2.4.3、正则表达式
只需要用 ~/表达式/, 匹配时用:需要匹配的字符=~/正则/;
def email = "2463983565@qq.com"
def isEmail = email ==~ /[\w.]/
println(isEmail)
2.4.4、被弱化的泛型
@CompileStatic
class LsitS {
List<String> list = ["123"];
}
2.4.5、Groovy的数字类型
在默认情况下groovy的数字类型都是BigDecimal类型,但是想要数字类型编程double,float,long类型的数字,只需要在数字后面加上c,f,l。
2.4.6、Boolean的自动转换
默认情况下groovy会把空字符串、0,null的if条件语句转成false,其他的转成true,这个特性和js、python一样
2.4.7、map语法糖
groovy允许我们把一个变量当做map的key或者value
def key = 1;
def value = 2;
def map = [(key): value]
println(map)
2.5、内置用法
2.5.1、自定义不存在方法的调用逻辑
class AAA {
def methodMissing(String name, args) {
println("没有这个方法")
}
}
def aaa = new AAA()
aaa.dw();
2.5.2、使用@Delegate
注解,可以实现方法的拷贝
class B{
@Delegate final Person person; // 将person中的所有方法拷贝过来
}
2.6、DSLs
2.6.1、基本使用
- 可以通过
delegate
属性可以直接实现
package dsl
public class SMS {
def form(String a) {
println("from ${a}")
}
def to(String a) {
println("to ${a}")
}
def body(String body) {
println("body:${body}")
}
def bodyDSL(String dsl) {
println("dsl:${dsl}")
}
def send() {
println("send..........")
}
def static send(block) {
def msm = new SMS();
block.delegate = msm;
block();
msm.send()
}
}
SMS.send({
form: "fromD"
to: "toD"
body: "I am body"
})
- 另一个dsl例子
show = { println(it) }
sq_root = { Math.sqrt(it) }
def please(action) {
[
then: {
what ->
[
of: { n -> action(what(n)) }
]
}
]
}
please(show).then(sq_root).of(100)
2.6.2、覆盖操作符
Operator | Method |
---|---|
a + b | a.plus(b) |
a - b | a.minus(b) |
a * b | a.multiply(b) |
a ** b | a.power(b) |
a / b | a.div(b) |
a % b | a.mod(b) |
a | b | a.or(b) |
a & b | a.and(b) |
a ^ b | a.xor(b) |
a++ | a.next() |
a– | a.previous() |
a[b] | a.getAt(b) |
a[index] = c | a.putAt(index, c) |
a << b | a.leftShift(b) |
a >> b | a.rightShift(b) |
a >>> b | a.rightShiftUnsigned(b) |
a >>> b | a.leftShiftUnsigned(b) |
switch(a){case (b): } | b.isCase(a) |
if(a) | a.asBoolean() |
~a | a.bitwiseNegate() |
-a | a.negative() |
+a | a.positive() |
a as b | a.asType(b) |
a == b | a.equals(b) |
a != b | !a.equals(b) |
a <=> b | a.compareTo(b) |
a > b | a.compareTo(b) > 0 |
a < b | a.compareTo(b) < 0 |
a >= b | a.compareTo(b) >= 0 |
a <= b | a.compareTo(b) <= 0 |
2.6.3、操作属性get|set
class MyList {
def list = [1, 2, 3, 4]
def setAt(Integer a) {
this.list.add(a)
}
}
MyList l = new MyList();
def list = l.getList()
println(list)
2.6.4、魔法方法
class MyList {
def propertyMissing(String name) {
println("属性:${name}不存在")
}
def methodMissing(String name) {
println("方法:${name}不存在")
}
}
2.7、trait关键字
traits关键字相当于jdk8的接口类,可以实现默认方法。也可抽象方法。
- 如果定义抽象方法时,要加上abstract关键字
- 可以实现具体的方法
2.8、函数式编程
2.8.1、基本使用
list = [1, 2, 4, 6, 8]
// 函数和闭包
static def finds(list, tester) {
for (item in list) {
if (tester(item)) {
return item
}
}
}
def i = finds(list, {
it > 2
})
println(i)
2.8.2、@Immutable
注解 (类似final)
放在类上,可以对所有的属性进行final的操作相同。
2.8.3、利用groovy的迭代方法进行流畅操作
// 批量截取字符串
list = ["dwawa", "dwawa", "dwawa", "dwawa"]
def collect = list.collect(it -> {
it.substring(1)
})
println(list)
println(collect)
// 判断若干个对象的name的谁的最长
def student1 = new Student("31233123123123")
def student2 = new Student("3123123123")
def student3 = new Student("3123213123dsa3123")
list = []
list.add(student1)
list.add(student2)
list.add(student3)
def studentName =
list
.findAll((item) -> { item.name != null })
.collect((item) -> { item.name })
.inject("") { n1, n2 ->
{
n1.length() >= (((n2 as String).length()) as Integer) ? n1 : n2
}
}
println(studentName)
2.8.4、curry(咖喱)方法
可以预设一些参数
con = { x, y -> return x + y }
br = con.curry("dwa")
println(br("x"))
// 返回值为dwax
2.8.5、业务处理逻辑
class A {
static print(name) { println("${name}") }
}
[1, 2, 3, 4, 4, 5].each { A.print(it) }
2.8.6、防止递归溢出
@TailRecursive
// 这个注解会将方法放入堆里面,而不是压栈