Gradle学习——Groovy基础

Groovy官方文档:The Apache Groovy programming language - Documentation (groovy-lang.org)

1. 概述

借用一下Apache官方的图

image-20220703142755139

大体上看,官方将Groovy描述为一个Java平台上的多面手

这里列举了很多内容,我们主要需要了解到Groovy是基于JVM的面向对象编程语言就行了

2. 编写与调试步骤

  • 目录创建build.gradle文件

  • build.gradle文件中创建task

  • task中用Groovy编写逻辑

  • build.gradle所在的目录下运行gradle <task名称>

3. 变量定义

1
2
3
def a = 1    // 根据初始化的值,推断为int类型 
int b = 2 // 指明类型为int
def c = "3" // 推断为String

image-20220703152340601

默认情况下的访问修饰符都是public

4. 方法定义

与变量的定义非常类似,如果指明返回类型就可以不使用def,默认情况下访问修饰符类型也是public

1
2
3
def add(a, b) {
println a + b
}

参数也可以不声明类型,依赖于调用的时候进行推断

image-20220703155330059

image-20220703155258563

调用的地方根据传入参数的类型进行了推断,确定了定义的参数类型

1
2
3
4
int minus(a, b) {
println a - b
a - b // 自动作为返回值
}

甚至可以在调用时不写括号

1
minus a, b   // 调用时可省略括号

方法体中如果没有return,那么最后一行内容会作为方法的返回值

注意:

  • 语句后的分号可以省略
  • 方法的括号可以省略
  • 参数类型可以省略
  • return语句也可以省略

5. 类

1
2
3
4
5
6
7
8
9
class Person {     // 定义类
String name
Integer age = 18
def gender = "male"

def sayHello() {
println "Hello, my name is " + name
}
}
1
2
3
def person = new Person()   // 实例化
person.name = "Bob"
person.sayHello()

image-20220703165005881

默认的类修饰符是public
并且没有设置可见修饰符的字段会自动生成对应的settergetter

image-20220703165210941

image-20220703165228971

6. 语句

6.1. 断言

首先需要注意,Groovy的断言一直处于开启状态,可以用作单元测试

1
assert 1 + 1 == 3

这是一条简单的断言,很显然,这将会失败

断言失败时,程序会抛出异常,并且中止

image-20220703170510424

那么,我们根据错误去检查原因,并修复

如果断言成功,并不会有什么事情发生

6.2. for循环

关于for循环,Groovy首先支持Java的for(int i = 0;i < N;i ++)for(i in array)这两种形式的循环语句

另外还支持一种for in loop形式,能够支持多种类型的遍历

1
2
3
4
// 遍历区间
for (i in 0..5) {
println i
}

image-20220703173459074

1
2
3
4
// 遍历列表
for (i in ['a', 'b', 'c', 'd']) {
println i
}

image-20220703173713089

1
2
3
4
// 遍历Map
for (entry in ['9' : 'CF', '11' : 'RW', '7' : 'LF'].entrySet()) {
println entry.key + ' : ' + entry.value
}

image-20220703174154731

6.3. switch语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def response = 500  // 自己可以换
switch (response) {
case 404: // 单个值匹配
println 'Not Found'
break
case [401, 403]: // 列表内容匹配
println 'Unauthorized or Forbidden'
break
case 500..505: // 区间内容匹配
println 'Server Problem'
break
case 200:
println 'OK'
break
default:
println 'Other Problem'
break
}

除此以外还可以进行类型匹配,能够处理的case类型比较多

7. 数据类型

Groovy所支持的数据类型主要包括:

  • Java中的基本数据类型
  • Groovy中的容器类
  • 闭包

7.1. 字符串

首先,需要注意,在Groovy中有两种字符串类型

  • 普通字符串String
  • 插值字符串GString

7.1.1. 单引号字符串

其实单引号和双引号都可以表示字符串,但是但因不支持插值,因此是纯常量

1
'Tears and Rain'

7.1.2. 双引号字符串

双引号除了单引号的字符串常量功能,还支持插值

1
2
def value = 'Rain'
"Tears and $value"

插值以$开头,表达式需要用{}括起来

7.1.3. 三引号字符串

在单引号常量的基础上添加了格式,但不支持插值

1
2
3
4
5
def str =
'''Tears
and
Rain'''
println str

image-20220704230111401

String不可变,GString可变,即使字面量相同,hashCode也可能不同,因此应当避免使用GString作为Map的Key

7.2. List

Groovy的集合类是对Java集合类的加工

因此Groovy中List就对应Java中的List,并且默认实现类是ArrayList

1
2
def list = [1, 2, 3]
assert list instanceof List

在Groovy中,使用as进行强制转换

1
2
def linkedList = list as LinkedList
assert linkedList instanceof LinkedList

元素的获取直接采用[],根据索引获取元素

这里的索引可正可负,分别对应正数和倒数的顺序

1
2
3
def list = [1, 2, 3]
assert list[0] == 1
assert list[-1] == 3

并且,使用<<可以进行末尾元素的追加

1
2
3
def list = [1, 2, 3]
list << 4 // 末尾追加
println list

image-20220706235406241

7.3. Map

创建同样使用[],不过其中的内容是键值对,并且这里的Map的默认实现使用的是LinkedHashMap

1
2
def map = [one: '1', two: '2', three: '3']   // 键值对
println map

但是需要注意的是,key的表示,key默认为字符串(尽管没加引号)

取值的方式,则是通过[]加上key

1
println map['one']   // 这个时候又需要加上引号了

因为之前说了,key默认会为字符串,那么变量如何表示?

image-20220708231636025

这样直接拿去用,自然key变成key1这个字符串,而非其内容(并未高亮显示)

image-20220708231741423

这里就需要加上括号,现在就高亮了

1
2
def key1 = 'one'
def map = [(key1): '1', two: '2', three: '3'] // 这里()特殊了这个key,表明它还拥有变量的身份

7.4. 闭包

闭包实际上代表的是一个代码块,而它的行为则由你进行定义

在结构上,闭包分为两个部分:参数列表语句

大概的格式为

1
{ 参数列表 -> 语句 }

其中,参数列表是可选的,如果参数列表只有一个参数,那么Groovy会将其默认为it

1
2
3
4
// 测试代码
task test {
println it // 其实就是前面的task
}

以上没有使用到参数列表

也可以指定参数列表

1
2
3
4
// 测试代码
task test {
it -> println it
}

闭包实质上是一个Closure实例

1
2
3
def add = {
String a, String b -> println a + b
}

闭包可以看作是方法,根据参数列表传入参数,执行语句

1
2
3
4
5
def add = {
String a, String b -> println a + b
}
add("1", "2") // 直接调用
add.call("1", "2") // 通过call()调用

image-20220709074955052

1
2
3
4
def isTwo = {
int i -> i == 2 // 返回值
}
println isTwo(1)

image-20220709074820771

7.5. I/O操作

I/O操作无外乎写入读取,这样的操作在使用Gradle构建应该很常见

7.5.1. 写入

image-20220709080707372

一会儿会在这里创建一个文件

1
2
3
4
5
6
def path = "C:\\Develop\\groovy_projects\\test\\mapping.txt"  // 文件路径
def file = new File(path) // 文件对象
file.withPrintWriter {
it.println("Happy birthday!") // 按行写入
it.println("My Love!")
}

这里按照路径创建了一个文件

image-20220709080946751image-20220709080946753

打开可以看到一共两行内容,这就写入成功了

image-20220709081009743

7.5.2. 读取

既然创建了对应的文件,并且写入了内容,那么接下来将文件的内容读取并输出到控制台上

1
2
3
4
5
def path = "C:\\Develop\\groovy_projects\\test\\mapping.txt"
def file = new File(path)
file.eachLine { // 将内容按行输出
println it
}

image-20220709081525024

甚至可以更精简一些

1
2
3
def path = "C:\\Develop\\groovy_projects\\test\\mapping.txt"
def file = new File(path)
println file.text // 全部输出

7.6. 语法糖

7.6.1. 判断列表

1
2
3
4
def name = []
if (name) { // 判断了!null且不为[]
println name
}

7.6.2. 空判断

使用.?进行调用,可以对调用方施加if(调用方!=null)的判断

这比Java中层层相扣的空指针判断要舒服很多

7.6.3. with

可用于简化对同一对象的操作

1
2
3
4
5
6
def p = new Person()
p.with {
name = 'Bob'
age = 10
}
println p.name