Apache Groovy是一种强大的,可选择类型和动态的语言,具有静态类型和静态编译功能,对于旨在通过简洁,熟悉和易于学习的语法提高开发人员生产力的Java平台。 它可以与任何Java程序顺利集成,并立即为您的应用程序提供强大的功能,包括脚本功能,特定于域的语言编写,运行时和编译时元编程和函数式编程。

安装

最简单无脑的方式:

1
$ brew install groovy

IDE 推荐 Intellij IDEA,支持自动补全,API 文档以及源码查看,Mac 上需要配置 Groovy SDK,通过 brew 安装的 Groovy SDK 路径为 /usr/local/Cellar/groovy/2.4.15/libexec,该文件夹是隐藏的需要执行 ⌘+⇧+. 显示出隐藏文件夹才能选择该目录

基本语法

单引号、双引号、三单引号、三双引号

单引号双引号的都可以互相在内部嵌套:

1
2
'Hello "World"'
"Hello 'World'"

它们的区别在于单引号中不能使用表达式,同样也不能使用转义符,双引号则可以
三单引号三双引号单引号双引号的基础上多了支持原样输出的功能

类型

Groovy 同时支持动态类型和静态类型,所以它定义变量的方式也会有很多种:

1
2
3
4
x = 1
def y = 2
int z = 3
def int w = 4

循环

支持 whileforfor-inupto

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// $it 表示当前索引,起始位置是 1 到 10
1.upto(10){
println "this is $it"
}

// $it 表示当前索引,起始位置是 0 到 10
10.times {
println("this is $it");
}

// $it 表示当前索引,起始位置是 2,步进是 2,不包含 10
2.step(10,2){
println("this is $it");
}

as 关键字

在Groovy语言中,进行强制类型转换使用的是 as 加上要转换的类型

1
2
List list = ['a','b']
ArrayList list1 = list as ArrayList

方法

方法可以接收任意数量的参数,且可以设置参数的默认值。定义参数时,不必显式定义类型。可以添加修饰符,如public,private和protected。默认情况下,如果未提供可见性修饰符,则该方法为public

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 函数的写法
def method(){
println "Hello"
}
// 带有返回值函数写法
def print(){
return "Hello"
}

// 可以省略return关键字
def methodWithRetrnKeywords(){
"Hello"
}

// 同java一样,return后的语句不执行
def methodWithRetrnKeywords2(){
return "Hello"
println "i can't run"
}

// 这是一个错误的示例,这种情况不能省略 return
def methodWithRetrnKeywords3(){
"Hello"
println "i can't run"
}

// 带有参数默认值的方法定义,该参数是可选的
def paramsWithDefaultValue(num = 100) {
println num
}

// Groovy还把最后一个为数组的形参视为可选的
def task(name,String[] details){
println "$name - $details"
}

def printName(name) {
println name
}

// 可以省略括号直接调用
printName 'kevin'

IO

提供一个 IO 的工具类 FileUtil.groovy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// 读取文件内容
def readFile(fileName) {
File newFile = new File(fileName)
return newFile.text
}

def writeFile(fileName, content) {
if (!isFileExist(fileName)){
return false
}
new File(fileName).withWriter('utf-8') {
writer -> writer.writeLine content
}
}

def writeFileAppend(fileName, content) {
if (!isFileExist(fileName)){
return false
}
new File(fileName).withWriterAppend('utf-8') {
writer -> writer.writeLine content
}
}

def isFileExist(fileName){
file = new File(fileName)
return file.isFile()
}

def isDirectory(fileName){
return new File(fileName).isDirectory()
}

def mkdirDir(fileName){
return new File(fileName).mkdir()
}

def delFile(fileName){
return new File(fileName).delete()
}

def copyFileContent(targetFileName, copyFileName){
file = new File(targetFileName)
copyFile = new File(copyFileName)
return file << copyFile.text
}

def getFileSize(fileName){
return new File(fileName).length()
}

def getFileAbsolutePath(fileName){
return new File(fileName).absolutePath
}

引用外部脚本文件

如果想要在一个 Groovy 脚本中调用另一个 Groovy 脚本中的函数,需要注意:

1
2
3
4
5
6
7
8
9
10
// 直接包含了另外一个 groovy 文件内容
evaluate(new File("fileName"))

// 如果是同级目录调用另外一个 groovy 脚本
fileUtil = new FileUtil()
println fileUtil.readFile("fileName")

// 如果不是同级目录,则需要在被引用的 groovy 脚本中加入 package 声明,声明为项目绝对路径即可
util = new utils.Util()
println util.readFile("fileName")

范围

  • 1..10 - 包含范围的示例
  • 1 .. <10 - 独占范围的示例
  • ‘a’..’x’ - 范围也可以由字符组成
  • 10..1 - 范围也可以按降序排列
  • ‘x’..’a’ - 范围也可以由字符组成并按降序排列

列表

  • [11,12,13,14] - 整数值列表
  • [‘Angular’,’Groovy’,’Java’] - 字符串列表
  • [1,2,[3,4],5] - 嵌套列表
  • [‘Groovy’,21,2.11] - 异构的对象引用列表
  • [] - 一个空列表

Map

  • [‘TopicName’:’Lists’,’TopicName’:’Maps’] - 具有TopicName作为键的键值对的集合及其相应的值
  • [:] - 空映射

特征

它们可以被看作是承载默认实现和状态的接口,使用 trait 关键字定义trait

1
2
3
4
5
6
7
8
9
10
11
12
13
14
trait IUser {
def getName() {
println 'Kevin'
}
}

class User implements IUser {

}

user = new User()
user.getName()

// output:kevin

安全导航操作符 - ?.

安全导航(safe-navigation)操作符(?.)在安全的情况下才会去调用指定的方法或者属性

1
2
3
4
5
6
7
8
9
10
11
class Userc {
def i = 1000
}

user = new User()
user.getName()
user = null
// output null
println user?.i
// throw NullPointerException
println user.i

枚举

1
2
3
enum CoffeeSize {
SHORT, SMALL, MEDIUM, LARGE, MUG
}

函数

1
2
3
4
5
6
7
8
9
10
11
String getString(){
return "hello world"
}

def getDef(){
return "hello world"
}

void printSomething(){
println "hello worlld"
}

闭包

闭包是一个短的匿名代码块。一个方法可以将闭包作为参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
name = 'kevin'

def clo = {params -> println "$params + $name"}

def getUser(name, Closure clo) {
clo.call(name)
}

// 声明了变量的闭包
getUser('hello', clo)

// 匿名闭包
getUser('world', {params -> println "$params + $name"})

// 如果闭包只有一个参数,就可以用 it 这个特殊的参数名来代表
getUser('world', {println "$it + $name"})

// 如果最后一个参数是闭包,可以将闭包附加到方法调用上
getUser('world'){println "$it + $name"}

// 如果函数只有一个参数且是闭包,调用该函数时可以直接省略小括号
def withoutParams(Closure closure){
closure.call('Hello World')
}

withoutParams {
println "this is $it"
}