1. 概述

本文将深入解析 Groovy 中的 def 关键字。作为一门运行在 JVM 上的动态语言,Groovy 提供了可选的类型机制,而 def 正是实现这一机制的重要组成部分。

2. def 关键字的作用

def 用于声明无类型变量或函数,体现 Groovy 的动态类型特性。

当我们不确定变量或方法返回值类型时,可以使用 def,让 Groovy 在运行时根据赋值自动推断类型:

def firstName = "Samwell"  
def listOfCountries = ['USA', 'UK', 'FRANCE', 'INDIA']

上面代码中,firstName 被推断为 String 类型,listOfCountries 则是 ArrayList

我们也可以用 def 定义方法的返回值类型:

def multiply(x, y) {
    return x * y
}

此时 multiply() 方法可以返回任意类型,具体取决于传入的参数。

3. 使用 def 声明变量

使用 def 声明变量时,Groovy 会将其初始化为 NullObject,值为 null

def list
assert list.getClass() == org.codehaus.groovy.runtime.NullObject
assert list.is(null)

一旦赋值,Groovy 会根据赋值内容动态决定其类型:

list = [1,2,4]
assert list instanceof ArrayList

如果变量类型需要动态变化,使用 def 是最佳选择:

def rate
assert rate == null

rate = 12
assert rate instanceof Integer

rate = "Not Available"
assert rate instanceof String

rate = [1, 4]
assert rate instanceof List

⚠️ 对比:若用 int rate = 20 声明,后续赋值为 ListString 会抛出 GroovyCastException

4. def 用于方法定义

def 也可用于定义返回值类型不固定的函数,这是 Groovy 动态特性的体现之一:

def divide(int x, int y) {
    if (y == 0) {
        return "Should not divide by 0"
    } else {
        return x / y
    }
}

assert divide(12, 3) instanceof BigDecimal
assert divide(1, 0) instanceof String

当然,也可以用来定义无返回值的方法:

def greetMsg() {
    println "Hello! I am Groovy"
}

5. def 与显式类型对比

使用 def 和显式类型时需要注意以下几点:

  • 避免冗余写法,例如 def int count,应使用 int countdef count

  • 推荐省略参数类型,如:

    // 不推荐
    void multiply(def x, def y)
    
    // 推荐
    void multiply(x, y)
    
  • 不要在构造函数中使用 def

6. def 与 Java 中 Object 的对比

如果你熟悉 Java,可能会觉得 def 类似于 Object 类型,确实如此:

def fullName = "Norman Lewis"

等价于 Java 中:

Object fullName = "Norman Lewis";

但 Groovy 的 def 更加灵活,支持动态类型推断和方法调用。

7. def@TypeChecked

如果你习惯 Java 这类强类型语言,可能会担心 Groovy 的动态类型是否会导致类型错误。不用担心,Groovy 提供了 @TypeChecked 注解来启用编译期类型检查。

例如:

@TypeChecked
class DefUnitTest extends GroovyTestCase {

    def multiply(x, y) {
        return x * y
    }
    
    int divide(int x, int y) {
        return x / y
    }
}

此时,multiply() 方法因为使用了 def,编译会失败:

[Static type checking] - Cannot find matching method java.lang.Object#multiply(java.lang.Object).
Please check if the declared type is correct and if the method exists.

解决办法:使用 TypeCheckingMode.SKIP 跳过特定方法的类型检查:

@TypeChecked(TypeCheckingMode.SKIP)
def multiply(x, y)

8. 总结

Groovy 的 def 关键字是其动态类型特性的核心体现。它允许我们:

  • 声明动态类型变量
  • 定义返回类型灵活的方法
  • 在需要时结合 @TypeChecked 实现类型安全

虽然它提供了灵活性,但也要求开发者具备良好的编码习惯,避免滥用导致代码难以维护。

最终,def 是写好动态 Groovy 代码的重要工具,用得恰当能显著提升开发效率。

如需查看完整示例代码,可访问 GitHub 项目仓库


原始标题:Groovy def Keyword | Baeldung