Groovy 的核心语法
太好了!欢迎来到 Groovy 的世界。对于初学者来说,Groovy 是一门非常友好的语言,尤其是如果你已经有 Java 的基础,会发现它非常容易上手。如果没有 Java 基础也没关系,Groovy 的语法清晰而简洁。
我会从最基础的部分开始,为你梳理 Groovy 的核心语法。
1. Groovy 是什么?
Groovy 是一种基于 JVM(Java 虚拟机)的动态语言。这意味着:
- 它和 Java 是“亲戚”: Groovy 完全兼容 Java 语法。你甚至可以直接把
.java
文件重命名为.groovy
来运行(当然,不推荐这么做)。 - 它比 Java 更“灵活”和“简洁”: Groovy 提供了更简单的语法、强大的特性(如闭包、动态类型),让你用更少的代码完成更多的工作。
- 它常用于: 构建工具(Gradle)、自动化脚本、测试框架(Spock)以及快速的应用程序原型开发。
2. 搭建环境与运行代码
最快的方式是使用 Groovy Web Console: https://groovyconsole.appspot.com/
你可以在浏览器里直接编写和运行 Groovy 代码,无需安装任何东西。
如果你想在本地运行,需要先安装 JDK,然后安装 Groovy SDK。
一个简单的 Groovy 脚本 HelloWorld.groovy
:
// 单行注释
println "Hello, World!" // 不需要分号,加上也没错
/*多行注释
*/
3. 基础语法要点
变量定义 (Variables)
Groovy 支持 动态类型(像 Python/JS)和 静态类型(像 Java)。
// 1. 动态类型:使用 def 关键字
def name = "Alice" // 字符串
def age = 30 // 整数
def score = 95.5 // 浮点数
def isStudent = true // 布尔值println name.class // 输出:class java.lang.String// 2. 静态类型:明确指定类型
String job = "Developer"
int year = 2024// 重新赋值
name = "Bob" // OK
// year = "Two thousand" // 错误!静态类型检查,不能将字符串赋给整型变量
字符串 (Strings)
Groovy 的字符串非常强大,尤其是 GString(插值字符串)。
// 1. 单引号字符串:普通字符串,不支持插值
def singleQuote = 'I am $name'
println singleQuote // 输出:I am $name// 2. 双引号字符串:支持插值(核心优势!)
def doubleQuote = "I am $name, and I am ${age + 1} years old next year."
println doubleQuote // 输出:I am Bob, and I am 31 years old next year.// 3. 三引号字符串:支持多行
def multiLine = '''Line 1Line 2Line 3
'''
println multiLine
集合 (Collections)
Groovy 为 List 和 Map 提供了极其简便的语法和强大的方法。
List (列表)
// 1. 定义List
def list = [1, 2, 3, 4] // 默认是 ArrayList
println list[0] // 输出 1 (索引从0开始)
println list[-1] // 输出 4 (支持负索引,从末尾开始)// 2. 添加元素
list << 5 // 等价于 list.add(5)
list += 6// 3. 常用方法
list.each { println it } // 遍历每个元素,`it`是默认参数名
def doubled = list.collect { it * 2 } // 映射为新列表 [2, 4, 6, 8, 10, 12]
def evens = list.findAll { it % 2 == 0 } // 查找所有偶数 [2, 4, 6]
Map (映射/字典)
// 1. 定义Map
def map = [name: "Alice", age: 30, "job": "Developer"] // 键默认是字符串,可加引号也可不加// 2. 访问元素
println map.name // Alice (类属性方式)
println map['age'] // 30 (类数组方式)
println map.get('job') // Developer (方法方式)// 3. 添加/修改元素
map.country = 'USA'
map['age'] = 31// 4. 遍历
map.each { key, value -> println "$key: $value"
}
闭包 (Closures)
闭包是 Groovy 的灵魂,它是一个可被延迟执行的代码块,类似于 Java 8 的 Lambda表达式。
// 1. 定义一个闭包
def greet = { name ->println "Hello, $name!"
}// 2. 调用闭包
greet("Bob") // 输出:Hello, Bob!// 3. 作为方法参数(非常常见)
// 假设有一个方法:def runTwice(Closure code) { code(); code() }
def runTwice(code) {code()code()
}runTwice { -> println "Running!" } // 输出两次 "Running!"// 4. 隐式参数 `it`
// 如果一个闭包只有一个参数,你可以省略它的定义,用 `it` 来访问
def printIt = { println it }
printIt("Hello") // 输出:Hellolist.each { println it } // 这里的 `it` 就是列表中的每一个元素
方法 (Methods)
方法定义使用 def
关键字(除非有明确的返回类型)。
// 1. 定义方法
def add(a, b) {return a + b
}
// return 可省略,方法默认返回最后一行表达式的值
def multiply(a, b) { a * b }// 2. 调用方法
def result = add(2, 3)
println result // 5// 3. 带默认参数的方法
def say(message, to = 'World') {println "$message, $to!"
}
say("Hi") // 输出:Hi, World!
say("Hello", "Alice") // 输出:Hello, Alice!
条件与循环 (Condition & Loop)
和 Java 类似,但更简洁。
// 1. 条件语句 if-else (和Java完全一样)
def x = 10
if (x > 5) {println "x is large"
} else if (x > 0) {println "x is small"
} else {println "x is negative"
}// 2. 循环
// 传统 for 循环
for (int i = 0; i < 5; i++) {println i
}// 范围循环 (更Groovy的风格)
for (i in 0..4) { // 0到4(包含4)println i
}(0..4).each { i -> println i } // 用闭包的方式,更函数式
4. 一个综合小例子
// 定义一个任务列表
def tasks = [[name: 'Learn Groovy', time: 60],[name: 'Write Code', time: 120],[name: 'Have Dinner', time: 30]
]// 1. 打印所有任务
println "All tasks:"
tasks.each { println "- ${it.name} (${it.time} mins)" }// 2. 找出耗时超过1小时的任务
println "\nLong tasks:"
def longTasks = tasks.findAll { it.time > 60 }
longTasks.each { task ->println "- ${task.name}"
}// 3. 计算总耗时
def totalTime = tasks.collect { it.time }.sum()
// 更简洁的写法:def totalTime = tasks.sum { it.time }
println "\nTotal time needed: $totalTime minutes"
学习建议
- 多动手: 在 Groovy Web Console 上把上面的例子都敲一遍,并尝试修改它们。
- 善用闭包: 理解
each
,collect
,findAll
,find
这些闭包方法是用好 Groovy 的关键。 - 查阅文档: 遇到问题,优先查看官方文档:Groovy Documentation
当然!对于初学者来说,理解这些闭包方法是Groovy(或类似语言如Kotlin)中非常强大和有趣的一步。它们让你能用非常简洁、易读的方式处理和操作集合(如列表、映射等)。
我会用尽可能简单的方式,配合例子来讲解。
首先,什么是闭包?
你可以把闭包(Closure) 想象成一个“打包好的代码块”或者一个“匿名方法”,它可以被传递、赋值给变量,或者作为参数传递给其他方法(就像我们下面要讲的这些)。在语法上,它通常被包裹在花括号 {}
中。
例如,定义一个简单的闭包:
def sayHello = { println "Hello!" }
// 执行它
sayHello() // 输出: Hello!
一个带参数的闭包:
def greet = { name -> println "Hello, ${name}!" }
greet("World") // 输出: Hello, World!
在集合操作中,我们经常把闭包作为参数传递。
现在,我们来看你问的这几个方法。假设我们有一个水果列表:
def fruits = ["Apple", "Banana", "Orange", "Kiwi"]
1. each
- 遍历执行
- 目的:遍历集合中的每个元素,并对每个元素执行一些操作(比如打印它)。它像是加强版的
for
循环。 - 返回值:返回集合本身。这意味着它不会改变或创建新的集合。
- 什么时候用:当你只是想对集合的每个元素做点什么事(比如打印、计算、修改外部变量),但不关心最终结果时。
例子:
// 只是打印每个水果
fruits.each { fruit ->println fruit
}
// 输出:
// Apple
// Banana
// Orange
// Kiwi// 它也可以写成一行(默认参数是 it)
fruits.each { println it }// 因为它返回原集合,所以可以链式调用(但通常不这么干)
fruits.each { println it }.each { println it.toUpperCase() }
关键点:each
是用来做事的,不是用来获取结果的。
2. collect
- 变换收集
- 目的:变换集合中的每个元素,并将变换后的结果收集到一个新的集合中。在其他语言里,这个方法通常叫
map
。 - 返回值:返回一个新的列表,包含所有变换后的元素。原集合不会被改变。
- 什么时候用:当你需要基于原集合创建一个内容不同但大小通常相同的新集合时。
例子:
// 把每个水果名变成大写,并收集到一个新列表里
def upperCaseFruits = fruits.collect { fruit ->fruit.toUpperCase()
}
println upperCaseFruits // 输出: [APPLE, BANANA, ORANGE, KIWI]
println fruits // 原列表不变: [Apple, Banana, Orange, Kiwi]// 也可以计算每个水果名字的长度
def nameLengths = fruits.collect { it.length() }
println nameLengths // 输出: [5, 6, 6, 4]
关键点:collect
是用来创造新东西的。
3. findAll
- 查找所有
- 目的:过滤集合,找出所有满足某个条件的元素。
- 返回值:返回一个新的列表,包含所有满足条件的元素。如果没找到,返回空列表。原集合不变。
- 什么时候用:当你需要从集合中筛选出符合特定规则的所有元素时。
例子:
// 找出所有名字长度大于5的水果
def longNameFruits = fruits.findAll { fruit ->fruit.length() > 5
}
println longNameFruits // 输出: [Banana, Orange]// 找出所有名字以 "A" 开头的水果
def aFruits = fruits.findAll { it.startsWith("A") }
println aFruits // 输出: [Apple]
关键点:findAll
是“我全都要”(符合条件的)。
4. find
- 查找单个
- 目的:查找并返回第一个满足条件的元素。
- 返回值:返回找到的第一个元素。如果什么都没找到,则返回
null
。 - 什么时候用:当你确信只有一个元素符合条件,或者你只关心找到的第一个元素时。
例子:
// 找到第一个名字以 "B" 开头的水果
def firstBFruit = fruits.find { fruit ->fruit.startsWith("B")
}
println firstBFruit // 输出: Banana// 尝试找一个不存在的
def notFound = fruits.find { it == "Grape" }
println notFound // 输出: null
关键点:find
是“我只要第一个”。
总结与对比
方法 | 目的 | 返回值 | 是否改变原集合 |
---|---|---|---|
each | 遍历执行操作 | 原集合本身 | 否 |
collect | 变换每个元素 | 新的集合 | 否 |
findAll | 过滤出所有符合条件的 | 新的集合 | 否 |
find | 查找第一个符合条件的 | 单个元素 或 null | 否 |
一个综合小例子
def numbers = [1, 2, 3, 4, 5, 6]// 1. 用 each 打印每个数
numbers.each { println it }// 2. 用 collect 创建一个每个数平方的新列表
def squares = numbers.collect { it * it } // [1, 4, 9, 16, 25, 36]// 3. 用 findAll 找出所有的偶数
def evens = numbers.findAll { it % 2 == 0 } // [2, 4, 6]// 4. 用 find 找出第一个大于3的数
def firstBigNumber = numbers.find { it > 3 } // 4
希望这个解释能帮助你理解!最好的学习方式就是打开一个编辑器,自己创建列表和映射,然后亲手试试这些强大的方法。玩得开心!