找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1378

积分

0

好友

186

主题
发表于 4 天前 | 查看: 16| 回复: 0

Groovy 作为一门基于 JVM 的动态编程语言,兼具 Java 的稳定性与脚本语言的灵活性,在自动化测试、DevOps、数据处理等领域应用广泛。本文按“基础语法 → 核心特性 → 高级能力 → 实战与优化”的路径,配合可直接编译运行的示例,帮助你快速建立 Groovy 的知识体系并落地到项目中。

参考文档:Groovy 官方文档:https://groovy-lang.org/documentation.html

一、Groovy 简介与环境搭建

1.1 什么是 Groovy?

Groovy 是基于 JVM 的动态脚本语言,由 James Strachan 于 2003 年创建。它完全兼容 Java 语法,同时吸收了 Python、Ruby 等语言的表达优势:更简洁的语法、更强的元编程能力、更丰富的内置 API。Groovy 代码可直接编译为 Java 字节码,无缝运行在 JVM 上,并能与 Java 类库互操作(适合在现有 Java 生态中渐进式引入)。

1.2 环境搭建(Maven 方式)

在 Java 项目中集成 Groovy,推荐用 Maven 管理依赖。下面是完整的 pom.xml 示例(基于 Groovy 4.0.20):

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.jam.demo</groupId>
    <artifactId>groovy-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <groovy.version>4.0.20</groovy.version>
        <lombok.version>1.18.30</lombok.version>
        <spring-boot.version>3.2.5</spring-boot.version>
        <fastjson2.version>2.0.47</fastjson2.version>
        <mybatis-plus.version>3.5.5</mybatis-plus.version>
        <mysql.version>8.0.36</mysql.version>
    </properties>
    <!-- 父依赖:Spring Boot 最新稳定版 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>${spring-boot.version}</version>
        <relativePath/>
    </parent>
    <dependencies>
        <!-- Groovy核心依赖 -->
        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <version>${groovy.version}</version>
            <type>pom</type>
        </dependency>
        <!-- Spring Boot Starter -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
            <scope>provided</scope>
        </dependency>
        <!-- FastJSON2 -->
        <dependency>
            <groupId>com.alibaba.fastjson2</groupId>
            <artifactId>fastjson2</artifactId>
            <version>${fastjson2.version}</version>
        </dependency>
        <!-- MyBatis-Plus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>
        <!-- MySQL驱动 -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>${mysql.version}</version>
            <scope>runtime</scope>
        </dependency>
        <!-- Swagger3 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-boot-starter</artifactId>
            <version>3.0.0</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <!-- Groovy编译插件 -->
            <plugin>
                <groupId>org.codehaus.gmavenplus</groupId>
                <artifactId>gmavenplus-plugin</artifactId>
                <version>3.0.0</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>testCompile</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <sourceEncoding>${project.build.sourceEncoding}</sourceEncoding>
                    <targetBytecodeVersion>17</targetBytecodeVersion>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

二、Groovy 基础语法(兼容 Java,更简洁)

2.1 变量定义

Groovy 同时支持动态类型与静态类型:可以用 def 省略类型,也可以显式指定类型(与 Java 兼容)。

2.1.1 基本语法
/**
 * 变量定义示例
 * @author ken
 */
// 动态类型:def关键字,类型由赋值自动推断
def name = "Groovy" // String类型
def age = 30 // Integer类型
def isEnable = true // Boolean类型

// 静态类型:显式指定类型(兼容Java)
String title = "Groovy语法指南"
Integer count = 100
Boolean flag = false

// 常量定义:final关键字(与Java一致)
final String VERSION = "4.0.20"
2.1.2 变量作用域

Groovy 的变量作用域与 Java 类似:局部变量、成员变量、静态变量。

/**
 * 变量作用域示例
 * @author ken
 */
class VariableScopeDemo {
    // 成员变量(实例变量)
    String memberVar = "成员变量"
    // 静态变量(类变量)
    static String staticVar = "静态变量"

    void testScope() {
        // 局部变量
        def localVar = "局部变量"
        println("局部变量:${localVar}")
        println("成员变量:${memberVar}")
        println("静态变量:${staticVar}")
    }
}

// 运行测试
new VariableScopeDemo().testScope()
// 输出结果:
// 局部变量:局部变量
// 成员变量:成员变量
// 静态变量:静态变量

2.2 数据类型

Groovy 的核心类型与 Java 一致(基本类型 + 包装类型),并扩展了 GString、Range 等更贴近脚本/DSL 的类型。

2.2.1 基本数据类型(与 Java 完全兼容)
/**
 * 基本数据类型示例
 * @author ken
 */
// 整数类型
byte b = 10
short s = 200
int i = 1000
long l = 10000000000L

// 浮点类型
float f = 3.14f
double d = 3.1415926

// 字符类型
char c = 'A'

// 布尔类型
boolean bool = true

// 输出类型信息
println("byte类型:${b.class}") // class java.lang.Byte
println("int类型:${i.class}") // class java.lang.Integer
println("double类型:${d.class}") // class java.lang.Double
println("char类型:${c.class}") // class java.lang.Character
2.2.2 Groovy 扩展类型
  • GString(可插值字符串):在字符串中直接插入变量/表达式,用 ${} 包裹,比 Java 拼接更清爽。
/**
 * GString示例
 * @author ken
 */
def name = "Groovy"
def version = "4.0.20"

// 单引号字符串:无插值功能(与Java一致)
def singleQuoteStr = 'Hello, ${name}!' 
// 双引号字符串:支持插值(GString类型)
def doubleQuoteStr = "Hello, ${name}! Version: ${version}"
// 三引号字符串:支持多行文本和插值
def multiLineStr = """
Hello, ${name}!
This is a multi-line string.
Version: ${version}
"""

println(singleQuoteStr) // 输出:Hello, ${name}!
println(doubleQuoteStr) // 输出:Hello, Groovy! Version: 4.0.20
println(multiLineStr) 

// 验证类型
println(doubleQuoteStr.class) // class groovy.lang.GString
println(singleQuoteStr.class) // class java.lang.String
  • Range(范围类型)start..end(闭区间)或 start..<end(左闭右开),可用于整数、字符、日期等。
/**
 * Range示例
 * @author ken
 */
// 整数范围(闭区间:1到5,包含5)
def intRange = 1..5
// 整数范围(左闭右开:1到5,不包含5)
def intRangeOpen = 1..<5
// 字符范围
def charRange = 'a'..'e'
// 日期范围
def dateStart = new Date()
def dateEnd = new Date() + 7 // 7天后
def dateRange = dateStart..dateEnd

// 遍历Range
println("整数闭区间遍历:")
intRange.each { println(it) }

println("整数左闭右开区间遍历:")
intRangeOpen.each { println(it) }

println("字符范围遍历:")
charRange.each { println(it) }

// Range常用方法
println("intRange是否包含3:${intRange.contains(3)}")
println("intRange的长度:${intRange.size()}")
println("intRange的第一个元素:${intRange.from}")
println("intRange的最后一个元素:${intRange.to}")

2.3 运算符

Groovy 支持 Java 的所有运算符,并补充了不少常用“语法糖”。

2.3.1 基础运算符(与 Java 一致)
/**
 * 基础运算符示例
 * @author ken
 */
def a = 10
def b = 3

// 算术运算符
println("a + b = ${a + b}")
println("a - b = ${a - b}")
println("a * b = ${a * b}")
println("a / b = ${a / b}")
println("a % b = ${a % b}")
println("a ** b = ${a ** b}") // 幂运算,Groovy扩展

// 比较运算符
println("a == b ? ${a == b}")
println("a > b ? ${a > b}")
println("a < b ? ${a < b}")

// 逻辑运算符
def flag1 = true
def flag2 = false
println("flag1 && flag2 = ${flag1 && flag2}")
println("flag1 || flag2 = ${flag1 || flag2}")
println("!flag1 = ${!flag1}")
2.3.2 Groovy 扩展运算符
  • 安全导航运算符(?.:对象为 null 时直接返回 null,避免 NPE。
/**
 * 安全导航运算符示例
 * @author ken
 */
class User {
    String name
    Integer age
}

def user1 = new User(name: "张三", age: 25)
def user2 = null

println("user1姓名:${user1?.name}")
println("user2姓名:${user2?.name}")
  • Elvis 运算符(?::简化空值兜底,等价于 obj != null ? obj : 默认值
/**
 * Elvis运算符示例
 * @author ken
 */
def user = null
def defaultName = "未知用户"

// 等价于:def userName = user != null ? user.name : defaultName
def userName = user?.name ?: defaultName
println(userName)

// 非空场景
def user3 = new User(name: "李四", age: 30)
def userName3 = user3?.name ?: defaultName
println(userName3)
  • 安全类型转换运算符(as?:转换失败返回 null,而非抛 ClassCastException
/**
 * 安全类型转换运算符示例
 * @author ken
 */
def obj1 = "123"
def obj2 = "abc"

def num1 = obj1 as? Integer
println("num1类型:${num1.class},值:${num1}")

def num2 = obj2 as? Integer
println("num2:${num2}")
  • *展开运算符(``)**:把集合元素“展开”为独立参数。
/**
 * 展开运算符示例
 * @author ken
 */
def list = [1, 2, 3]

// 定义一个接收多个参数的方法
def sum(a, b, c) {
    return a + b + c
}

// 使用展开运算符传递集合元素
def total = sum(*list)
println("总和:${total}")

// 字符串展开(转换为字符数组)
def str = "abc"
def charList = [*str]
println(charList)

2.4 流程控制语句

Groovy 的流程控制与 Java 基本一致,但在遍历 Range、集合、Map 等场景更简洁。

2.4.1 if-else
/**
 * if-else示例
 * @author ken
 */
def score = 85

if (score >= 90) {
    println("优秀")
} else if (score >= 80) {
    println("良好")
} else if (score >= 60) {
    println("及格")
} else {
    println("不及格")
}
// 输出:良好
2.4.2 for 循环
/**
 * for循环示例
 * @author ken
 */
// 1. 传统for循环(与Java一致)
for (int i = 0; i < 5; i++) {
    println("传统循环:${i}")
}

// 2. 增强for循环(遍历集合/数组,与Java一致)
def list = [1, 2, 3, 4, 5]
for (def item : list) {
    println("增强循环:${item}")
}

// 3. Groovy简化循环(遍历Range)
for (i in 1..5) {
    println("简化循环:${i}")
}

// 4. 遍历Map
def map = [name: "Groovy", version: "4.0.20", author: "James Strachan"]
for (entry in map) {
    println("Map键:${entry.key},值:${entry.value}")
}
2.4.3 while 与 do-while
/**
 * while与do-while示例
 * @author ken
 */
// while循环
def count = 0
while (count < 3) {
    println("while循环:${count}")
    count++
}

// do-while循环(至少执行一次)
def num = 0
do {
    println("do-while循环:${num}")
    num++
} while (num < 3)
2.4.4 switch-case(更灵活)
/**
 * switch-case示例
 * @author ken
 */
def obj = "Groovy"

switch (obj) {
    case 1:
        println("整数1")
        break
    case "Groovy":
        println("字符串:Groovy")
        break
    case [1, 2, 3]:
        println("集合中的元素")
        break
    case Integer:
        println("Integer类型")
        break
    case String:
        println("String类型")
        break
    default:
        println("默认情况")
}
// 输出:字符串:Groovy

三、Groovy 核心特性(相对 Java 的效率优势)

3.1 集合操作(List、Map、Set)

Groovy 对 Java 集合做了大量增强,常见操作(遍历、过滤、映射、聚合)更省代码。

3.1.1 List(列表)
/**
 * List操作示例
 * @author ken
 */
// 定义List(默认ArrayList)
def list = [1, 2, 3, 4, 5]

// 1. 访问元素
println("第一个元素:${list[0]}")
println("最后一个元素:${list[-1]}") // 负索引:从尾部开始
println("索引1到3的元素:${list[1..3]}") // Range切片

// 2. 添加元素
list.add(6)
list << 7
list.addAll([8, 9])
println("添加元素后:${list}")

// 3. 删除元素
list.remove(0)
list.remove(Integer.valueOf(9))
list -= 8
println("删除元素后:${list}")

// 4. 遍历List
println("each遍历:")
list.each { element ->
    println(element)
}

println("eachWithIndex遍历:")
list.eachWithIndex { element, index ->
    println("索引${index}:${element}")
}

// 5. 过滤与转换
def evenList = list.findAll { it % 2 == 0 }
println("偶数列表:${evenList}")

def doubleList = list.collect { it * 2 }
println("元素翻倍后:${doubleList}")

// 6. 聚合操作
def sum = list.sum()
def max = list.max()
def min = list.min()
def average = list.average()
println("求和:${sum},最大值:${max},最小值:${min},平均值:${average}")
3.1.2 Map(映射)
/**
 * Map操作示例
 * @author ken
 */
def map = [name: "Groovy", version: "4.0.20", author: "James Strachan"]

// 1. 访问元素
println("name:${map.name}")
println("version:${map['version']}")
println("author:${map.get('author')}")
println("不存在的键:${map.get('desc', '无描述')}")

// 2. 添加元素
map.desc = "基于JVM的动态脚本语言"
map.put("year", 2003)
map << [language: "Java"]
println("添加元素后:${map}")

// 3. 删除元素
map.remove("year")
map -= "language"
println("删除元素后:${map}")

// 4. 遍历Map
map.each { entry ->
    println("键:${entry.key},值:${entry.value}")
}

map.each { key, value ->
    println("键:${key},值:${value}")
}

println("遍历键:")
map.keySet().each { println(it) }

println("遍历值:")
map.values().each { println(it) }

// 5. 过滤与转换
def filteredMap = map.findAll { key, value ->
    value.toString().length() > 5
}
println("筛选后:${filteredMap}")

def entryList = map.collect { key, value ->
    [key: key, value: value]
}
println("转换为List:${entryList}")
3.1.3 Set(集合)
/**
 * Set操作示例
 * @author ken
 */
def set = [1, 2, 2, 3, 3, 3] as Set
println("Set初始化(去重):${set}")

set.add(4)
set << 5
println("添加元素后:${set}")

set.remove(2)
set -= 3
println("删除元素后:${set}")

def set1 = [1, 2, 3, 4] as Set
def set2 = [3, 4, 5, 6] as Set

def union = set1 + set2
println("并集:${union}")

def intersection = set1.intersect(set2)
println("交集:${intersection}")

def difference = set1 - set2
println("差集:${difference}")

set1.each { println(it) }

3.2 方法定义与调用

Groovy 方法更“短平快”:可省略返回类型和 return,支持默认参数、命名参数、变长参数等。

3.2.1 基础方法定义
/**
 * 基础方法定义示例
 * @author ken
 */
def printHello(String name) {
    println("Hello, ${name}!")
}

def add(Integer a, Integer b) {
    a + b
}

Integer multiply(Integer a, Integer b) {
    return a * b
}

printHello("Groovy")
def sum = add(10, 20)
println("10 + 20 = ${sum}")
def product = multiply(10, 20)
println("10 * 20 = ${product}")
3.2.2 可选参数与默认参数
/**
 * 可选参数与默认参数示例
 * @author ken
 */
def sayHello(String name, String prefix = "Hello", String suffix = "!") {
    "${prefix}, ${name}${suffix}"
}

def msg1 = sayHello("张三", "Hi", "!!!")
println(msg1)

def msg2 = sayHello("李四")
println(msg2)

def msg3 = sayHello(suffix: "~", name: "王五", prefix: "Hi")
println(msg3)
3.2.3 变长参数
/**
 * 变长参数示例
 * @author ken
 */
def sumAll(Integer... args) {
    args.sum()
}

def total1 = sumAll(1, 2, 3, 4, 5)
println("总和1:${total1}")

def nums = [6, 7, 8]
def total2 = sumAll(*nums)
println("总和2:${total2}")
3.2.4 方法调用省略括号
/**
 * 方法调用省略括号示例
 * @author ken
 */
def printMsg(String msg) {
    println(msg)
}

printMsg "Hello, Groovy!"

def appendStr(String str1, String str2) {
    str1 + str2
}

def result = appendStr "Hello, ", "Groovy"
println result

3.3 类与对象

Groovy 类定义兼容 Java,同时提供了更顺手的属性访问与构造方式。

3.3.1 简化的类定义
/**
 * 简化类定义示例
 * @author ken
 */
class User {
    String name
    Integer age
    String email
}

def user = new User(name: "张三", age: 25, email: "zhangsan@example.com")

println("姓名:${user.name}")
println("年龄:${user.age}")

user.age = 26
println("修改后的年龄:${user.age}")
3.3.2 构造器
/**
 * 构造器示例
 * @author ken
 */
class User {
    String name
    Integer age

    User(String name, Integer age) {
        this.name = name
        this.age = age
    }

    @Override
    String toString() {
        "User{name='${name}', age=${age}}"
    }
}

def user1 = new User("李四", 30)
println(user1)

class User2 {
    String name
    Integer age

    User2() {}

    @Override
    String toString() {
        "User2{name='${name}', age=${age}}"
    }
}

def user2 = new User2(name: "王五", age: 35)
println(user2)
3.3.3 Groovy 注解简化类定义
/**
 * Groovy注解简化类定义示例
 * @author ken
 */
import groovy.transform.ToString
import groovy.transform.EqualsAndHashCode
import groovy.transform.TupleConstructor
import groovy.transform.Data

@ToString
class User3 {
    String name
    Integer age
}

def user3 = new User3("赵六", 40)
println(user3)

@EqualsAndHashCode
class User4 {
    String name
    Integer age
}

def user4_1 = new User4("孙七", 45)
def user4_2 = new User4("孙七", 45)
def user4_3 = new User4("周八", 50)
println("user4_1 == user4_2 ? ${user4_1 == user4_2}")
println("user4_1 == user4_3 ? ${user4_1 == user4_3}")

@TupleConstructor
class User5 {
    String name
    Integer age
}

def user5 = new User5("吴九", 55)
println(user5.name)
println(user5.age)

@Data
class User6 {
    String name
    Integer age
}

def user6 = new User6("郑十", 60)
println(user6)
def user6_2 = new User6("郑十", 60)
println("user6 == user6_2 ? ${user6 == user6_2}")

3.4 闭包(Closure)

闭包是 Groovy 的核心能力之一:可执行代码块,可捕获上下文,可作为参数传递,是构建 DSL、回调逻辑的基础。

3.4.1 闭包基础定义与调用
/**
 * 闭包基础示例
 * @author ken
 */
// 1. 无参数闭包
def noParamClosure = {
    println("无参数闭包")
}

noParamClosure()
noParamClosure.call()

// 2. 带参数闭包
def paramClosure = { String name, Integer age ->
    println("姓名:${name},年龄:${age}")
}

paramClosure("张三", 25)
paramClosure.call("李四", 30)

// 3. 单参数闭包:默认参数it
def singleParamClosure = {
    println("默认参数it:${it}")
}

singleParamClosure("Groovy")
3.4.2 闭包作为方法参数
/**
 * 闭包作为方法参数示例
 * @author ken
 */
def processList(List list, Closure closure) {
    list.each { element ->
        closure.call(element)
    }
}

def list = [1, 2, 3, 4, 5]
processList(list) { element ->
    println("元素:${element * 2}")
}

processList(list) {
    println("元素:${it * 3}")
}
3.4.3 闭包捕获上下文变量
/**
 * 闭包捕获上下文变量示例
 * @author ken
 */
def outerVar = "外部变量"

def closure = {
    println("捕获外部变量:${outerVar}")
}

closure()

outerVar = "修改后的外部变量"
closure()

def count = 0
def incrementClosure = {
    count++
}

incrementClosure()
incrementClosure()
println("count:${count}")
3.4.4 闭包的委托(Delegate)
/**
 * 闭包委托示例
 * @author ken
 */
class DelegateDemo {
    String name = "DelegateDemo"

    void testClosure() {
        def closure = {
            println("this:${this.name}")
            println("owner:${owner.name}")
            println("delegate:${delegate.name}")
        }

        closure()
    }
}

new DelegateDemo().testClosure()

class AnotherDelegate {
    String name = "AnotherDelegate"
}

def demo = new DelegateDemo()
def anotherDelegate = new AnotherDelegate()
def closure = {
    println("delegate:${delegate.name}")
}

closure.delegate = anotherDelegate
closure()

四、Groovy 高级特性

4.1 元编程(Metaprogramming)

Groovy 支持运行时动态修改类行为、添加方法、拦截方法调用等能力(MetaClass、Expando 等),适合 AOP 增强、DSL 框架、快速扩展。

4.1.1 Expando(动态类)
/**
 * Expando示例
 * @author ken
 */
def user = new Expando()

user.name = "张三"
user.age = 25

user.sayHello = {
    println("Hello, ${name}!")
}

user.calculate = { Integer a, Integer b ->
    a + b
}

println("姓名:${user.name},年龄:${user.age}")
user.sayHello()
def sum = user.calculate(10, 20)
println("10 + 20 = ${sum}")
4.1.2 元类(MetaClass)
/**
 * MetaClass示例
 * @author ken
 */
class User {
    String name
    Integer age
}

User.metaClass.sayHello = {
    println("Hello, ${name}! 年龄:${age}")
}

User.metaClass.static.createUser = { String name, Integer age ->
    new User(name: name, age: age)
}

def user = User.createUser("李四", 30)
user.sayHello()

User.metaClass.invokeMethod = { String methodName, Object[] args ->
    if (methodName == "sayHello") {
        println("拦截sayHello方法,自定义实现:Hello, ${delegate.name}(拦截后)")
    } else {
        delegate.metaClass.getMetaMethod(methodName, args).invoke(delegate, args)
    }
}

user.sayHello()

4.2 异常处理

Groovy 异常处理与 Java 基本一致,支持 try-catch-finally,也支持多异常合并捕获(Groovy 3.0+)。

/**
 * 异常处理示例
 * @author ken
 */
def divide(Integer a, Integer b) {
    if (b == 0) {
        throw new ArithmeticException("除数不能为0")
    }
    a / b
}

try {
    def result = divide(10, 0)
    println("结果:${result}")
} catch (ArithmeticException e) {
    println("捕获异常:${e.message}")
} catch (Exception e) {
    println("捕获通用异常:${e.message}")
} finally {
    println("异常处理结束")
}

try {
    def list = [1, 2, 3]
    println(list[10])
    divide(10, 0)
} catch (ArrayIndexOutOfBoundsException | ArithmeticException e) {
    println("捕获多类型异常:${e.message}")
} finally {
    println("多异常处理结束")
}

4.3 文件操作

Groovy 文件 API 更贴近脚本场景,读写更简短,资源管理更省心。结合自动化脚本、构建任务、运维工具时尤其顺手(可扩展到 运维/DevOps 的常见场景)。

4.3.1 读取文件
/**
 * 文件读取示例
 * @author ken
 */
// 1. 读取文件所有内容(一行代码)
def content = new File("test.txt").text
println("文件内容:${content}")

// 2. 按行读取文件
def file = new File("test.txt")
// 方式1:eachLine(自动关闭流)
file.eachLine { line, lineNum ->
    println("第${lineNum}行:${line}")
}

// 方式2:readLines(返回所有行的List)
def lines = file.readLines()
lines.each { println(it) }

// 3. 读取文件流(手动处理)
file.withReader { reader ->
    String line
    while ((line = reader.readLine()) != null) {
        println(line)
    }
}
4.3.2 写入文件
/**
 * 文件写入示例
 * @author ken
 */
def file = new File("output.txt")

// 1. 覆盖写入文件(一行代码)
file.text = "Hello, Groovy!\n这是覆盖写入的内容"

// 2. 追加写入文件
file.append("\n这是追加的内容")

// 3. 按行写入文件
file.withWriter { writer ->
    writer.writeLine("第一行内容")
    writer.writeLine("第二行内容")
}

// 4. 写入集合内容
def lines = ["第三行内容", "第四行内容"]
file.withWriter { writer ->
    lines.each { writer.writeLine(it) }
}

4.4 数据库操作(结合 MyBatis-Plus)

Groovy 可无缝集成 MyBatis-Plus,实现常规 CRUD 与批处理能力。下面是基于 MySQL 8.0 的完整示例(数据库与中间件相关内容也可扩展阅读 数据库/中间件 方向的实践)。

4.4.1 配置文件(application.yml)
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/groovy_demo?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis-plus:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.jam.demo.entity
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

swagger:
  enabled: true
4.4.2 实体类(User.groovy)
/**
 * 用户实体类
 * @author ken
 */
package com.jam.demo.entity

import com.baomidou.mybatisplus.annotation.IdType
import com.baomidou.mybatisplus.annotation.TableId
import com.baomidou.mybatisplus.annotation.TableName
import io.swagger.annotations.ApiModel
import io.swagger.annotations.ApiModelProperty
import lombok.Data

import java.time.LocalDateTime

@Data
@TableName("t_user")
@ApiModel(description = "用户实体")
class User {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键ID")
    Integer id

    @ApiModelProperty(value = "用户名")
    String username

    @ApiModelProperty(value = "密码")
    String password

    @ApiModelProperty(value = "年龄")
    Integer age

    @ApiModelProperty(value = "创建时间")
    LocalDateTime createTime

    @ApiModelProperty(value = "更新时间")
    LocalDateTime updateTime
}
4.4.3 Mapper 接口(UserMapper.groovy)
/**
 * 用户Mapper
 * @author ken
 */
package com.jam.demo.mapper

import com.baomidou.mybatisplus.core.mapper.BaseMapper
import com.jam.demo.entity.User
import org.springframework.stereotype.Repository

@Repository
interface UserMapper extends BaseMapper<User> {
}
4.4.4 服务类(UserService.groovy)
/**
 * 用户服务类
 * @author ken
 */
package com.jam.demo.service

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
import com.jam.demo.entity.User
import com.jam.demo.mapper.UserMapper
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
class UserService extends ServiceImpl<UserMapper, User> {
    /**
     * 新增用户
     * @param user 用户实体
     * @return 新增成功的用户
     */
    @Transactional(rollbackFor = Exception.class)
    User addUser(User user) {
        save(user)
        return user
    }

    /**
     * 根据ID查询用户
     * @param id 主键ID
     * @return 用户实体
     */
    User getUserById(Integer id) {
        getById(id)
    }

    /**
     * 更新用户
     * @param user 用户实体
     * @return 是否更新成功
     */
    @Transactional(rollbackFor = Exception.class)
    boolean updateUser(User user) {
        updateById(user)
    }

    /**
     * 根据ID删除用户
     * @param id 主键ID
     * @return 是否删除成功
     */
    @Transactional(rollbackFor = Exception.class)
    boolean deleteUser(Integer id) {
        removeById(id)
    }
}
4.4.5 控制器(UserController.groovy)
/**
 * 用户控制器
 * @author ken
 */
package com.jam.demo.controller

import com.jam.demo.entity.User
import com.jam.demo.service.UserService
import io.swagger.annotations.Api
import io.swagger.annotations.ApiOperation
import io.swagger.annotations.ApiParam
import lombok.extern.slf4j.Slf4j
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.util.ObjectUtils
import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("/user")
@Api(tags = "用户管理接口")
@Slf4j
class UserController {
    @Autowired
    UserService userService

    @PostMapping("/add")
    @ApiOperation("新增用户")
    User addUser(@ApiParam(value = "用户实体", required = true) @RequestBody User user) {
        log.info("新增用户:{}", user)
        return userService.addUser(user)
    }

    @GetMapping("/{id}")
    @ApiOperation("根据ID查询用户")
    User getUserById(@ApiParam(value = "用户ID", required = true) @PathVariable Integer id) {
        log.info("查询用户ID:{}", id)
        User user = userService.getUserById(id)
        if (ObjectUtils.isEmpty(user)) {
            log.warn("用户ID:{} 不存在", id)
        }
        return user
    }

    @PutMapping("/update")
    @ApiOperation("更新用户")
    boolean updateUser(@ApiParam(value = "用户实体", required = true) @RequestBody User user) {
        log.info("更新用户:{}", user)
        if (ObjectUtils.isEmpty(user.getId())) {
            throw new IllegalArgumentException("用户ID不能为空")
        }
        return userService.updateUser(user)
    }

    @DeleteMapping("/{id}")
    @ApiOperation("根据ID删除用户")
    boolean deleteUser(@ApiParam(value = "用户ID", required = true) @PathVariable Integer id) {
        log.info("删除用户ID:{}", id)
        return userService.deleteUser(id)
    }
}
4.4.6 启动类(GroovyDemoApplication.groovy)
/**
 * 启动类
 * @author ken
 */
package com.jam.demo

import org.mybatis.spring.annotation.MapperScan
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication

@SpringBootApplication
@MapperScan("com.jam.demo.mapper")
class GroovyDemoApplication {
    static void main(String[] args) {
        SpringApplication.run(GroovyDemoApplication, args)
    }
}
4.4.7 SQL 脚本(创建表 t_user)
CREATE TABLE `t_user` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `username` varchar(50) NOT NULL COMMENT '用户名',
  `password` varchar(50) NOT NULL COMMENT '密码',
  `age` int DEFAULT NULL COMMENT '年龄',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

五、Groovy 与 Java 的差异对比

为了更快把握两者的“本质差异”,下面从语法、特性、使用场景等维度进行对比,并补充实际开发的影响点:

特性 Groovy Java 核心差异说明与实战影响
变量定义 支持 def 动态类型;静态类型也兼容 必须显式类型(Java 10+ 支持 var Groovy 更适合脚本/快速开发;Java 更适合强类型的大型工程
字符串 GString 插值(双引号、三引号) 仅拼接或 String.format Groovy 拼接日志、SQL 文本更省代码
集合操作 [ ][k:v],内建 each/findAll/collect new 创建,常用 Stream(Java 8+) Groovy 集合处理更短,适合数据处理脚本
方法定义 可省略返回类型/return;默认参数、命名参数 返回类型必须;默认参数需重载 Groovy 可减少大量模板方法
构造器 默认 Map 构造器 new User(name:"x") 通常手写或 Lombok Groovy 适合实体初始化与 DSL
闭包 原生 Closure,支持委托 Lambda 需函数式接口 Groovy 更适合 DSL/回调/配置式编程
元编程 MetaClass/Expando 运行时增强 不支持(需字节码工具) Groovy 动态扩展强,但需控制范围避免影响全局
异常处理 可省略 checked 异常声明;多异常捕获 checked 异常必须声明/捕获 Groovy 更利于脚本迭代;Java 更严格
文件操作 file.text/eachLine 简洁,自动管理资源 IO 代码相对繁琐 Groovy 用于脚本/工具类非常高效
空指针防护 ?.?: 需手动判空 Groovy 判空更自然,减少 NPE 风险
运算符重载 支持 不支持 Groovy 在领域模型表达上更灵活
注释 额外支持 shebang #! Groovy 脚本可直接运行(类 Unix 环境)

5.1 差异核心逻辑:动态 vs 静态

Groovy 的设计目标更偏向“减少样板代码、提升开发效率”;Java 更强调“类型安全、长期可维护性”。两者同在 JVM 上运行,字节码层面天然可互操作,因此工程实践中常见模式是:Groovy 负责脚本/工具/测试,Java 负责核心业务与接口契约

5.2 混合开发实战示例(Groovy + Java)

下面展示一种典型搭配:Groovy 实现文件工具类,Java 业务服务调用 Groovy 工具完成批量导入。

5.2.1 Groovy 工具类(FileUtils.groovy)
/**
 * 文件操作工具类(Groovy 实现,简化 IO 操作)
 * @author ken
 */
package com.jam.demo.util

import org.springframework.util.StringUtils

class FileUtils {
    /**
     * 读取文件内容(自动关闭资源,支持编码指定)
     * @param filePath 文件路径
     * @param charset 编码(默认 UTF-8)
     * @return 文件内容字符串
     */
    static String readFile(String filePath, String charset = "UTF-8") {
        if (!StringUtils.hasText(filePath)) {
            throw new IllegalArgumentException("文件路径不能为空")
        }
        def file = new File(filePath)
        if (!file.exists() || !file.isFile()) {
            throw new FileNotFoundException("文件不存在:${filePath}")
        }
        // Groovy 简化 API,自动关闭流
        file.getText(charset)
    }

    /**
     * 按行处理文件(支持大文件,避免内存溢出)
     * @param filePath 文件路径
     * @param closure 每行处理逻辑(闭包参数:行内容、行号)
     */
    static void processFileByLine(String filePath, Closure closure) {
        if (!StringUtils.hasText(filePath) || ObjectUtils.isEmpty(closure)) {
            throw new IllegalArgumentException("文件路径或处理逻辑不能为空")
        }
        def file = new File(filePath)
        if (!file.exists() || !file.isFile()) {
            throw new FileNotFoundException("文件不存在:${filePath}")
        }
        // 按行读取,自动关闭流,闭包传递处理逻辑
        file.eachLine { line, lineNum ->
            closure.call(line, lineNum)
        }
    }
}
5.2.2 Java 业务服务类(UserBusinessService.java)
/**
 * 用户业务服务(Java 实现,核心业务逻辑)
 * @author ken
 */
package com.jam.demo.service;

import com.jam.demo.entity.User;
import com.jam.demo.mapper.UserMapper;
import com.jam.demo.util.FileUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class UserBusinessService extends ServiceImpl<UserMapper, User> {

    /**
     * 从文件批量导入用户(调用 Groovy 工具类实现文件读取)
     * @param filePath 用户数据文件路径(每行格式:用户名,密码,年龄)
     * @return 导入成功的用户数量
     */
    @Transactional(rollbackFor = Exception.class)
    public int batchImportUserFromFile(String filePath) {
        log.info("开始从文件导入用户:{}", filePath);
        List<User> userList = new ArrayList<>();

        // 调用 Groovy 工具类的 processFileByLine 方法,传递 Java Lambda 作为闭包(Groovy 兼容 Java Lambda)
        FileUtils.processFileByLine(filePath, (line, lineNum) -> {
            log.debug("处理第 {} 行数据:{}", lineNum, line);
            if (ObjectUtils.isEmpty(line)) {
                log.warn("第 {} 行数据为空,跳过", lineNum);
                return;
            }
            // 解析行数据
            String[] parts = line.split(",");
            if (parts.length != 3) {
                log.error("第 {} 行数据格式错误,跳过:{}", lineNum, line);
                return;
            }
            String username = parts[0].trim();
            String password = parts[1].trim();
            Integer age;
            try {
                age = Integer.parseInt(parts[2].trim());
            } catch (NumberFormatException e) {
                log.error("第 {} 行年龄格式错误,跳过:{}", lineNum, line);
                return;
            }
            // 构建用户实体
            User user = new User();
            user.setUsername(username);
            user.setPassword(password);
            user.setAge(age);
            userList.add(user);
        });

        // 批量保存用户
        if (userList.isEmpty()) {
            log.warn("无有效用户数据可导入");
            return 0;
        }
        boolean success = saveBatch(userList);
        log.info("用户导入完成,有效数据行数:{},导入成功:{}", userList.size(), success);
        return success ? userList.size() : 0;
    }
}
5.2.3 测试验证(Groovy 测试类)
/**
 * 混合开发测试类
 * @author ken
 */
package com.jam.demo.test

import com.jam.demo.service.UserBusinessService
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest

@SpringBootTest
class MixedDevelopmentTest {
    @Autowired
    UserBusinessService userBusinessService

    def "测试从文件批量导入用户"() {
        given: "准备测试文件(user_import.txt),内容如下:"
        def testFile = new File("user_import.txt")
        testFile.text = """
zhangsan,123456,25
lisi,654321,30
wangwu,abc123,35
"""

        when: "调用导入方法"
        def importCount = userBusinessService.batchImportUserFromFile("user_import.txt")

        then: "验证导入结果"
        importCount == 3
        def userList = userBusinessService.list()
        userList.size() >= 3
        userList.any { it.username == "zhangsan" && it.age == 25 }
    }
}

5.3 差异总结与选型建议

  1. 优先选 Groovy 的场景  

    • 自动化脚本(部署脚本、数据迁移脚本、测试脚本)  
    • 工具类开发(文件操作、数据格式转换、集合处理)  
    • DSL 开发(Gradle 脚本、Jenkins Pipeline)  
    • 快速原型验证(迭代速度优先)
  2. 优先选 Java 的场景  

    • 核心业务逻辑(强调类型安全与可维护性)  
    • 强性能诉求模块(静态编译更易优化)  
    • 团队以 Java 为主、希望降低额外学习成本
  3. 混合开发建议  

    • Groovy 写“辅助性”代码:工具、脚本、测试  
    • Java 写“核心性”代码:接口、模型、业务服务  
    • 依托 Spring 生态共享依赖与上下文,实现无缝协作

六、Groovy 实战场景:从脚本到企业级应用

6.1 场景 1:自动化测试脚本(结合 JUnit 5)

/**
 * 用户服务单元测试
 * @author ken
 */
package com.jam.demo.test

import com.jam.demo.entity.User
import com.jam.demo.service.UserService
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import static org.assertj.core.api.Assertions.assertThat

@SpringBootTest
class UserServiceTest {
    @Autowired
    UserService userService

    @Test
    void "测试新增用户"() {
        def user = new User(username: "test_user", password: "test123", age: 28)

        def savedUser = userService.addUser(user)

        assertThat(savedUser).isNotNull()
        assertThat(savedUser.getId()).isGreaterThan(0)
        assertThat(savedUser.getUsername()).isEqualTo("test_user")
        assertThat(savedUser.getAge()).isEqualTo(28)
    }

    @Test
    void "测试根据ID查询用户"() {
        def user = new User(username: "query_user", password: "query123", age: 30)
        def savedUser = userService.addUser(user)

        def queriedUser = userService.getUserById(savedUser.getId())

        assertThat(queriedUser).isNotNull()
        assertThat(queriedUser.getId()).isEqualTo(savedUser.getId())
        assertThat(queriedUser.getUsername()).isEqualTo("query_user")
    }
}

6.2 场景 2:数据迁移脚本(批量处理数据库数据)

/**
 * 旧用户表到新用户表的数据迁移脚本
 * @author ken
 */
package com.jam.demo.script

import com.jam.demo.entity.OldUser
import com.jam.demo.entity.User
import com.jam.demo.mapper.OldUserMapper
import com.jam.demo.mapper.UserMapper
import com.jam.demo.util.DateUtils
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.CommandLineRunner
import org.springframework.stereotype.Component
import lombok.extern.slf4j.Slf4j
import com.google.common.collect.Lists

@Slf4j
@Component
class UserDataMigrationScript implements CommandLineRunner {
    @Autowired
    OldUserMapper oldUserMapper

    @Autowired
    UserMapper userMapper

    @Override
    void run(String... args) throws Exception {
        log.info("开始执行用户数据迁移脚本")

        int pageNum = 1
        int pageSize = 1000
        while (true) {
            def page = oldUserMapper.selectPage(new Page<>(pageNum, pageSize), null)
            if (page.getRecords().isEmpty()) {
                break
            }
            log.info("处理第 {} 页数据,共 {} 条", pageNum, page.getRecords().size())

            def userList = page.getRecords().collect { OldUser oldUser ->
                new User(
                    username: oldUser.getUserName(),
                    password: oldUser.getPassword(),
                    age: oldUser.getAge(),
                    createTime: DateUtils.parse(oldUser.getCreateTimeStr(), "yyyy-MM-dd HH:mm:ss"),
                    updateTime: new Date()
                )
            }

            Lists.partition(userList, 500).each { batch ->
                userMapper.insertBatchSomeColumn(batch)
            }

            pageNum++
        }

        log.info("用户数据迁移脚本执行完成")
    }
}

6.3 场景 3:Jenkins Pipeline 脚本(DevOps 自动化部署)

/**
 * Jenkins Pipeline 自动化部署脚本
 * @author ken
 */
pipeline {
    agent any

    environment {
        PROJECT_NAME = 'groovy-demo'
        GIT_REPO = 'https://gitee.com/xxx/groovy-demo.git'
        BRANCH = 'master'
        JAR_PATH = 'target/groovy-demo-1.0-SNAPSHOT.jar'
        DEPLOY_PATH = '/opt/apps'
    }

    stages {
        stage('拉取代码') {
            steps {
                echo "开始拉取 ${GIT_REPO} 仓库 ${BRANCH} 分支代码"
                git url: GIT_REPO, branch: BRANCH
            }
        }

        stage('编译构建') {
            steps {
                echo "开始编译构建项目"
                sh 'mvn clean package -Dmaven.test.skip=true'
            }
            post {
                success {
                    echo "编译构建成功,生成 jar 包:${JAR_PATH}"
                }
                failure {
                    echo "编译构建失败,请检查代码或依赖"
                    error "编译构建失败,终止 Pipeline"
                }
            }
        }

        stage('自动化测试') {
            steps {
                echo "开始执行自动化测试"
                sh 'mvn test'
            }
            post {
                success {
                    echo "自动化测试全部通过"
                }
                failure {
                    echo "自动化测试存在失败用例,请修复后重新构建"
                    error "自动化测试失败,终止 Pipeline"
                }
            }
        }

        stage('部署到服务器') {
            steps {
                echo "开始部署项目到服务器"
                sh "ssh root@192.168.1.100 'cd ${DEPLOY_PATH} && ./stop.sh'"
                sh "scp ${JAR_PATH} root@192.168.1.100:${DEPLOY_PATH}"
                sh "ssh root@192.168.1.100 'cd ${DEPLOY_PATH} && ./start.sh'"
            }
            post {
                success {
                    echo "项目部署成功!访问地址:http://192.168.1.100:8080"
                }
                failure {
                    echo "项目部署失败,请检查服务器连接或启动脚本"
                }
            }
        }
    }

    post {
        always {
            echo "Pipeline 执行完成,无论成功或失败都会执行"
            sh 'mvn clean'
        }
    }
}

6.4 场景 4:自定义 DSL(领域特定语言)

/**
 * 数据同步任务 DSL 定义与使用示例
 * @author ken
 */
package com.jam.demo.dsl

import lombok.Data

@Data
class SyncTask {
    String taskName
    String sourceTable
    String targetTable
    List<String> columns
    Closure whereClosure
    Closure transformClosure
}

class SyncTaskBuilder {
    SyncTask task = new SyncTask()

    def name(String taskName) {
        task.setTaskName(taskName)
    }

    def source(String sourceTable) {
        task.setSourceTable(sourceTable)
    }

    def target(String targetTable) {
        task.setTargetTable(targetTable)
    }

    def columns(List<String> columns) {
        task.setColumns(columns)
    }

    def where(Closure closure) {
        task.setWhereClosure(closure)
        closure.delegate = task
        closure.resolveStrategy = Closure.DELEGATE_FIRST
    }

    def transform(Closure closure) {
        task.setTransformClosure(closure)
        closure.delegate = task
        closure.resolveStrategy = Closure.DELEGATE_FIRST
    }

    SyncTask build() {
        if (!task.getTaskName()) throw new IllegalArgumentException("任务名称不能为空")
        if (!task.getSourceTable()) throw new IllegalArgumentException("源表不能为空")
        if (!task.getTargetTable()) throw new IllegalArgumentException("目标表不能为空")
        if (task.getColumns().isEmpty()) throw new IllegalArgumentException("同步字段不能为空")
        return task
    }
}

def syncTask(Closure closure) {
    def builder = new SyncTaskBuilder()
    closure.delegate = builder
    closure.resolveStrategy = Closure.DELEGATE_FIRST
    closure.call()
    return builder.build()
}

def userSyncTask = syncTask {
    name "用户数据同步任务"
    source "t_old_user"
    target "t_user"
    columns ["id", "username", "age", "create_time"]
    where {
        "age > 18 AND status = 1"
    }
    transform {
        "DATE_FORMAT(create_time, '%Y-%m-%d %H:%i:%s') AS create_time"
    }
}

class SyncTaskExecutor {
    static void execute(SyncTask task) {
        println "开始执行任务:${task.getTaskName()}"
        def columnsStr = task.getColumns().join(", ")
        def whereClause = task.getWhereClosure().call()
        def transformClause = task.getTransformClosure().call()
        def syncSql = """
INSERT INTO ${task.getTargetTable()} (${columnsStr})
SELECT ${transformClause ?: columnsStr} FROM ${task.getSourceTable()}
WHERE ${whereClause}
"""
        println "生成同步 SQL:\n${syncSql}"
        // jdbcTemplate.execute(syncSql)
        println "任务执行完成:${task.getTaskName()}"
    }
}

SyncTaskExecutor.execute(userSyncTask)

七、Groovy 性能优化与最佳实践

7.1 性能优化关键点

Groovy 的动态特性提升了表达力,但在热点路径上可能有额外开销。常见优化策略:

  1. 静态类型优化  
    • 热点方法/循环显式指定类型  
    • 使用 @CompileStatic 将代码静态编译,性能更接近 Java

示例:

import groovy.transform.CompileStatic

/**
 * 静态编译优化示例
 * @author ken
 */
@CompileStatic
class PerformanceOptimizedService {
    Integer calculateSum(List<Integer> list) {
        Integer sum = 0
        for (Integer num : list) {
            sum += num
        }
        return sum
    }
}
  1. 集合操作优化  

    • 避免在循环中频繁创建临时集合  
    • 大集合处理关注分批与流式处理,减少一次性装载与中间对象
  2. 元编程优化  

    • 动态增强应尽量放在初始化阶段  
    • 避免在热点代码里频繁修改 MetaClass(影响范围大、难排查)
  3. 文件操作优化  

    • 大文件优先 eachLine,避免 text 一次性读入内存  
    • 写入用 withWriter 减少 IO 次数

7.2 最佳实践

  1. 代码规范  

    • 工具/脚本可动态类型;核心业务建议静态类型或 @CompileStatic  
    • 命名与结构尽量对齐 Java 工程习惯,提升协作与维护性  
    • 避免闭包过度嵌套,控制复杂度
  2. 依赖管理  

    • 优先使用 Groovy 内建 API,避免重复引第三方  
    • 注意 Groovy 与 JDK 版本匹配(Groovy 4.x 推荐 JDK 11+;本文示例基于 JDK 17)
  3. 异常处理  

    • 核心业务优先捕获特定异常,避免无脑兜底 Exception  
    • 异常信息带上下文(参数、操作、环境),利于定位
  4. 测试规范  

    • 脚本/DSL 可用 Spock;企业应用核心逻辑建议 JUnit 5  
    • 覆盖动态特性(闭包委托、元编程扩展点),减少运行时意外

八、总结与学习资源

8.1 核心总结

Groovy 的优势在于“更少的样板代码 + 更强的表达能力”:字符串插值、集合高阶操作、闭包与 DSL、元编程能力,让它在脚本、工具、测试、DevOps 自动化领域非常高效。与 Java 混合使用时,建议把 Groovy 放在“效率优先”的外围层,把 Java 放在“稳定与契约优先”的核心层,从而兼顾迭代速度与系统稳定性。

8.2 权威学习资源

来自圈子: alphaFind



上一篇:Claude Code 项目介绍:把代码审查与验证流程搬到终端里
下一篇:ThreadLocal内存泄漏解析:弱引用设计原理与Netty的FastThreadLocal优化
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-24 21:10 , Processed in 0.297773 second(s), 38 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表