groovy闭包

你想理解 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"
                    }
                }
            }
        }
    }
}

三、闭包的关键总结

  1. 核心本质:闭包是可执行的代码块对象,支持参数、返回值,能访问外部变量;
  2. 简化语法 :单参数闭包可省略参数声明,用 it 指代参数;
  3. 高频场景:集合遍历 / 过滤 / 转换、Jenkins 流水线、动态生成业务逻辑;
  4. 可读性原则 :简单逻辑用 it,复杂逻辑 / 嵌套闭包显式声明参数名。

如果需要针对 Jenkins 流水线场景的闭包实战(如动态生成 stage、根据参数执行不同逻辑),我可以补充更贴合工作的示例。

相关推荐
jiang_changsheng1 分钟前
RTX 2080 Ti魔改22GB显卡的最优解ComfyUI教程
python·comfyui
R_.L3 分钟前
【QT】常用控件(按钮类控件、显示类控件、输入类控件、多元素控件、容器类控件、布局管理器)
开发语言·qt
Zach_yuan12 分钟前
自定义协议:实现网络计算器
linux·服务器·开发语言·网络
云姜.18 分钟前
java多态
java·开发语言·c++
CoderCodingNo27 分钟前
【GESP】C++五级练习题 luogu-P1865 A % B Problem
开发语言·c++·算法
陳103033 分钟前
C++:红黑树
开发语言·c++
一切尽在,你来39 分钟前
C++ 零基础教程 - 第 6 讲 常用运算符教程
开发语言·c++
泉-java40 分钟前
第56条:为所有导出的API元素编写文档注释 《Effective Java》
java·开发语言
0思必得041 分钟前
[Web自动化] Selenium处理滚动条
前端·爬虫·python·selenium·自动化
沈浩(种子思维作者)1 小时前
系统要活起来就必须开放包容去中心化
人工智能·python·flask·量子计算