你想理解 Groovy 中闭包(Closure)的核心概念,并通过实用示例掌握它的用法 ------ 闭包是 Groovy 最核心的特性之一,本质是「可复用的代码块」,能作为参数传递、赋值给变量,还能访问外部作用域的变量,比 Java 的 Lambda 更灵活。下面我会先讲核心概念,再用多个高频场景的示例帮你吃透闭包。
一、闭包的核心概念
1. 定义
闭包是 Groovy 中一种特殊的代码块,用 {} 包裹,可包含参数和执行逻辑,语法格式:
groovy
// 格式1:无参数闭包
{ 代码逻辑 }
// 格式2:有参数闭包(参数写在箭头前,多个参数用逗号分隔)
{ 参数1, 参数2 -> 代码逻辑 }
// 格式3:单参数简化(省略参数和箭头,用默认变量 it 指代参数)
{ 代码逻辑 } // 等价于 { it -> 代码逻辑 }
2. 核心特性
- 可赋值给变量:闭包本身是对象,可像普通变量一样赋值、传递;
- 访问外部变量:闭包能访问定义它的外部作用域的变量(无需传参);
- 灵活的参数 :支持默认参数、可变参数,单参数可省略声明(用
it); - 作为方法参数:Groovy 集合、IO 等 API 大量使用闭包作为参数,简化代码。
二、闭包的基础示例(从简单到复杂)
示例 1:基础闭包 ------ 赋值给变量并执行
这是最基础的用法,闭包赋值给变量后,通过 () 或 call() 执行:
groovy
// 1. 无参数闭包
def sayHello = { println "Hello Groovy!" }
sayHello() // 执行方式1:直接加括号,输出 "Hello Groovy!"
sayHello.call() // 执行方式2:call() 方法,效果相同
// 2. 单参数闭包(用默认变量 it)
def printNum = { println "数字:${it}" }
printNum(10) // 输出 "数字:10"
// 3. 多参数闭包(显式声明参数)
def add = { a, b -> println "a + b = ${a + b}" }
add(5, 3) // 输出 "a + b = 8"
// 4. 有返回值的闭包(最后一行表达式自动返回,无需 return)
def multiply = { a, b -> a * b }
def result = multiply(4, 5)
println "乘法结果:${result}" // 输出 "乘法结果:20"
示例 2:闭包访问外部变量(核心特性)
闭包能直接访问定义它的外部作用域变量,甚至修改(无需传参):
groovy
// 外部变量
def base = 10
// 闭包访问并修改外部变量
def calculate = { num ->
base += num // 修改外部变量
println "base + num = ${base}"
}
calculate(5) // base 变为 15,输出 "base + num = 15"
calculate(3) // base 变为 18,输出 "base + num = 18"
println "最终base:${base}" // 输出 "最终base:18"
示例 3:闭包作为方法参数(集合遍历,Jenkins 高频)
Groovy 集合(List/Map)的 each/find/collect 等方法都接受闭包作为参数,替代繁琐的循环:
groovy
// 1. List 遍历(each 方法 + 闭包)
def list = [1, 2, 3, 4, 5]
// 简化写法:单参数用 it
list.each { println "元素:${it}" }
// 输出:
// 元素:1
// 元素:2
// ...
// 带索引遍历(eachWithIndex + 多参数闭包)
list.eachWithIndex { num, index ->
println "索引${index}:${num}"
}
// 输出:
// 索引0:1
// 索引1:2
// ...
// 2. 集合过滤(findAll + 闭包):筛选偶数
def evenNums = list.findAll { it % 2 == 0 }
println "偶数列表:${evenNums}" // 输出 "偶数列表:[2, 4]"
// 3. 集合转换(collect + 闭包):所有元素翻倍
def doubleNums = list.collect { it * 2 }
println "翻倍列表:${doubleNums}" // 输出 "翻倍列表:[2, 4, 6, 8, 10]"
// 4. Map 遍历(闭包参数为 entry,key/value 可解构)
def map = [name: "张三", age: 20, city: "北京"]
map.each { key, value ->
println "${key}:${value}"
}
// 输出:
// name:张三
// age:20
// city:北京
示例 4:闭包作为方法的返回值(进阶)
闭包可作为方法返回值,实现 "动态生成逻辑":
groovy
// 定义方法,返回一个闭包(根据输入的运算符,生成对应的计算逻辑)
def getCalculator(String operator) {
switch (operator) {
case "+": return { a, b -> a + b }
case "-": return { a, b -> a - b }
case "*": return { a, b -> a * b }
default: return { a, b -> 0 }
}
}
// 获取加法闭包并执行
def add = getCalculator("+")
println "5 + 3 = ${add(5, 3)}" // 输出 "5 + 3 = 8"
// 获取乘法闭包并执行
def multiply = getCalculator("*")
println "4 * 6 = ${multiply(4, 6)}" // 输出 "4 * 6 = 24"
示例 5:闭包的默认参数和自定义参数名(避免 it 歧义)
当闭包逻辑复杂时,建议显式声明参数名,替代默认的 it,提升可读性:
groovy
// 反例:嵌套闭包用 it 导致歧义
def list = [[name: "张三", age:20], [name: "李四", age:25]]
// list.each { it.each { println it } } // 内层 it 指代什么?可读性差
// 正例:显式声明参数名
list.each { user -> // 外层参数名:user
user.each { key, value -> // 内层参数名:key/value
println "用户${user.name}的${key}:${value}"
}
}
// 输出:
// 用户张三的name:张三
// 用户张三的age:20
// 用户李四的name:李四
// 用户李四的age:25
示例 6:Jenkins 流水线中的闭包(实战核心)
Jenkins Pipeline 本质是 Groovy 脚本,闭包是流水线的核心语法(如 pipeline {}/stage {}/steps {} 都是闭包):
groovy
pipeline { // 最外层闭包
agent any
stages { // 嵌套闭包
stage('构建') { // 嵌套闭包
steps { // 嵌套闭包
script {
// 流水线中使用闭包遍历分支
def branches = ["master", "dev", "test"]
branches.each { branch -> // 业务逻辑闭包
echo "开始构建分支:${branch}"
git url: 'https://git.example.com/project.git', branch: branch
sh "mvn clean package"
}
}
}
}
}
}
三、闭包的关键总结
- 核心本质:闭包是可执行的代码块对象,支持参数、返回值,能访问外部变量;
- 简化语法 :单参数闭包可省略参数声明,用
it指代参数; - 高频场景:集合遍历 / 过滤 / 转换、Jenkins 流水线、动态生成业务逻辑;
- 可读性原则 :简单逻辑用
it,复杂逻辑 / 嵌套闭包显式声明参数名。
如果需要针对 Jenkins 流水线场景的闭包实战(如动态生成 stage、根据参数执行不同逻辑),我可以补充更贴合工作的示例。