ZetCode

Groovy Variables

last modified June 26, 2026

Variables store values that a program can read and modify. Groovy supports both dynamic and static variable declarations, giving developers the flexibility of a scripting language alongside the safety of a typed one. This tutorial covers every major aspect of variables in Groovy.

Basic Definition

A variable is a named storage location that holds a value. In Groovy, variables can be declared with the def keyword, with an explicit type, or with var for local type inference. The type can change at runtime when def is used.

Groovy compiles to JVM bytecode, so all Groovy types are ultimately Java types. Groovy adds dynamic dispatch and optional static typing on top of the Java type system.

def Keyword

The def keyword declares a variable whose type is determined at runtime by the assigned value.

DefKeyword.groovy
def name = "Alice"
def age = 30
def weight = 58.5
def active = true

println name
println age
println weight
println active

Each variable is assigned a value and Groovy infers the runtime type from that value. The def keyword signals that the type is not constrained at the declaration site.

Using def is idiomatic Groovy for script-level code and method local variables where the exact type is obvious from context.

$ groovy DefKeyword.groovy
Alice
30
58.5
true

Explicit Type Declaration

Variables can be declared with a specific Java or Groovy type instead of def. The type is then enforced at runtime.

ExplicitTypes.groovy
String language = "Groovy"
int year = 2003
double version = 4.0
boolean jvmBased = true

println "$language $version was released around $year"
println "JVM based: $jvmBased"

Explicit types document intent and allow IDEs and compilers to catch type mismatches early. Any value incompatible with the declared type triggers a runtime exception under normal Groovy compilation.

Common types are the standard Java primitives and their wrapper classes: int, long, double, boolean, String, BigDecimal.

$ groovy ExplicitTypes.groovy
Groovy 4.0 was released around 2003
JVM based: true

Dynamic Typing

A def variable is not bound to a fixed type and can be reassigned to a value of a different type.

DynamicTyping.groovy
def value = 42
println value.getClass().simpleName

value = "Groovy"
println value.getClass().simpleName

value = [1, 2, 3]
println value.getClass().simpleName

After each assignment, getClass reports the new runtime type. The variable itself is just a reference that can point to any object.

Dynamic typing is convenient for prototyping and scripting. For production code, explicit types or @CompileStatic are preferred.

$ groovy DynamicTyping.groovy
Integer
String
ArrayList

var Keyword

Groovy 3 introduced var for local variable type inference, similar to Java 10. The type is inferred from the initializer and is fixed thereafter.

VarKeyword.groovy
var message = "Hello, Groovy"
var count = 100
var prices = [9.99, 14.50, 3.75]

println message.toUpperCase()
println count * 2
println prices.sum()

var behaves like a statically typed variable: the inferred type is locked at declaration. Attempting to assign an incompatible value later causes a compile error under @CompileStatic.

Use var when the type is obvious from the right-hand side and you want the clarity of a fixed type without writing it out explicitly.

$ groovy VarKeyword.groovy
HELLO, GROOVY
200
28.24

Multiple Assignment

Groovy supports destructuring assignment, allowing several variables to be declared and assigned from a list in a single statement.

MultipleAssignment.groovy
def (first, second, third) = ["alpha", "beta", "gamma"]
println first
println second
println third

// Swap two variables
def a = 1
def b = 2
(a, b) = [b, a]
println "a=$a  b=$b"

The list on the right is unpacked into the declared variables in order. If the list is shorter than the variable list, the extra variables are assigned null.

Multiple assignment is especially useful for swapping values and unpacking method return values without a temporary variable.

$ groovy MultipleAssignment.groovy
alpha
beta
gamma
a=2  b=1

String Variables and GStrings

Groovy strings enclosed in double quotes are GStrings that support expression interpolation with the ${} syntax.

GStringExample.groovy
def firstName = "Jane"
def lastName = "Doe"
def age = 28

println "Name: $firstName $lastName"
println "Age: $age"
println "Born in: ${2026 - age}"
println "Upper: ${firstName.toUpperCase()}"

Simple variable references use $variable. Expressions and method calls require the full ${expression} form.

Single-quoted strings are plain java.lang.String objects and do not support interpolation. Triple-quoted variants of both exist for multi-line strings.

$ groovy GStringExample.groovy
Name: Jane Doe
Age: 28
Born in: 1998
Upper: JANE

Null Value

Any variable can hold null, representing the absence of a value. Groovy provides the safe-navigation operator ?. to avoid NullPointerExceptions.

NullExample.groovy
def username = null

// Safe navigation - returns null instead of throwing NPE
println username?.toUpperCase()

// Elvis operator - provide a default for null
def display = username ?: "Guest"
println display

// Null-safe assignment
username = "alice"
println username?.toUpperCase()

The ?. operator returns null when the receiver is null rather than throwing an exception. The Elvis operator ?: returns the left operand if it is non-null, otherwise the right operand.

$ groovy NullExample.groovy
null
Guest
ALICE

Constants

The final keyword prevents a variable from being reassigned after its initial assignment.

Constants.groovy
final double PI = 3.14159265358979
final int MAX_SIZE = 100
final String APP_NAME = "MyApp"

println PI
println MAX_SIZE
println APP_NAME

// PI = 3.14  // throws groovy.lang.ReadOnlyPropertyException

Attempting to reassign a final variable throws a ReadOnlyPropertyException at runtime. For compile-time enforcement, combine final with @CompileStatic.

Constants are typically written in UPPER_SNAKE_CASE when they represent fixed domain values or configuration, following Java conventions.

$ groovy Constants.groovy
3.14159265358979
100
MyApp

Variable Scope

Variables declared with def inside a class are instance fields. Variables declared inside a method or block are local to that scope.

VariableScope.groovy
class Counter {
    int count = 0  // instance variable

    void increment() {
        int step = 1  // local variable
        count += step
    }

    void display() {
        println "Count: $count"
    }
}

def c = new Counter()
c.increment()
c.increment()
c.increment()
c.display()

The local variable step exists only within the increment method. The instance variable count is shared across all method calls on the same object.

$ groovy VariableScope.groovy
Count: 3

Script Binding

In Groovy scripts, variables declared without def are stored in the script's Binding object and are accessible across methods in the same script.

ScriptBinding.groovy
message = "Hello from binding"  // no def - goes into binding

def printMessage() {
    println message  // accessible here
}

printMessage()

def localVar = "I am local"  // def - local to script body
println localVar

A variable without def in a script is a binding variable visible to all closures and methods in that script. A variable with def is local to the script's run method and not shared.

$ groovy ScriptBinding.groovy
Hello from binding
I am local

Primitive and Wrapper Types

Groovy automatically boxes primitive values into their wrapper types. Most Groovy code works with wrapper objects, though the compiler uses primitives internally for performance where possible.

PrimitiveTypes.groovy
int a = 10           // java.lang.Integer at runtime
long b = 100_000L
double c = 3.14
boolean d = false

println a.getClass().simpleName
println b.getClass().simpleName
println c.getClass().simpleName
println d.getClass().simpleName

Even though the variables are declared with primitive types, Groovy wraps them in their object counterparts so that methods like getClass can be called on them.

Underscores in numeric literals (e.g. 100_000L) are a Groovy feature that improves readability for large numbers.

$ groovy PrimitiveTypes.groovy
Integer
Long
Double
Boolean

Type Coercion

The as operator converts a value to a specified type, invoking Groovy's coercion mechanism.

TypeCoercion.groovy
def strNumber = "42"
def number = strNumber as int
println number + 8

def pi = 3.99
def truncated = pi as int
println truncated

def words = "Groovy" as List
println words

Coercing a string to int parses the string. Coercing a double to int truncates (not rounds) the value. Coercing a string to List splits it into a list of characters.

$ groovy TypeCoercion.groovy
50
3
[G, r, o, o, v, y]

Static Type Checking

The @groovy.transform.TypeChecked annotation enables compile-time type checking for a class or method, catching type errors before runtime.

TypeChecked.groovy
import groovy.transform.TypeChecked

@TypeChecked
class Calculator {

    int add(int a, int b) {
        a + b
    }

    double average(List<Integer> values) {
        values.sum() / values.size()
    }
}

def calc = new Calculator()
println calc.add(10, 20)
println calc.average([4, 8, 15, 16, 23, 42])

@TypeChecked ensures that method calls and variable assignments are type-safe at compile time. @CompileStatic goes further by also generating optimised bytecode without dynamic dispatch.

$ groovy TypeChecked.groovy
30
18.0

Variable Naming

Groovy follows Java naming conventions. Variable and method names use camelCase. Constants use UPPER_SNAKE_CASE. Class names use PascalCase.

VariableNaming.groovy
final int MAX_RETRIES = 3

def firstName = "Alice"
def lastName = "Smith"
def ageInYears = 30
def isActive = true

println "$firstName $lastName, age $ageInYears, active: $isActive"
println "Max retries: $MAX_RETRIES"

Descriptive names improve readability. Prefer isActive over flag, userCount over n. Avoid single-letter names except for short loop counters.

$ groovy VariableNaming.groovy
Alice Smith, age 30, active: true
Max retries: 3

Source

Groovy Syntax Documentation

This tutorial covered Groovy variable declarations, dynamic and static typing, GStrings, null handling, scope, type coercion, and compile-time type checking.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Groovy tutorials.