Beginner

Variables and Types in Groovy

Learn about variables, data types, and type conversions in Groovy with practical Docker-ready examples

Introduction

Groovy offers one of the most flexible type systems on the JVM. Unlike Java, where every variable requires an explicit type declaration, Groovy lets you choose between dynamic typing with def and explicit static typing — sometimes in the same file. This optional typing is one of Groovy’s defining features.

As a multi-paradigm language that runs on the JVM, Groovy gives you access to all of Java’s types while adding its own conveniences: native syntax for lists and maps, powerful string interpolation with GStrings, and seamless type coercion with the as keyword. You get the rapid prototyping feel of Python or Ruby with the ability to add Java-style type safety when you need it.

In this tutorial, you’ll learn how to declare variables, work with Groovy’s core data types, convert between types, and use constants. All examples are runnable with Docker — no local installation required.

Variable Declaration

Groovy provides two approaches to declaring variables: dynamic typing with def and explicit type declarations using Java types.

Create a file named variables.groovy:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// Dynamic typing with def
def name = "Groovy"
def year = 2003
def pi = 3.14159
def active = true

println "Language: ${name}"
println "First appeared: ${year}"
println "Pi: ${pi}"
println "Active: ${active}"

// Check the actual types at runtime
println ""
println "--- Runtime Types ---"
println "name is ${name.class.simpleName}"
println "year is ${year.class.simpleName}"
println "pi is ${pi.class.simpleName}"
println "active is ${active.class.simpleName}"

// Explicit type declarations (Java-style)
println ""
println "--- Explicit Types ---"
String greeting = "Hello from Groovy"
int count = 42
double ratio = 0.75
boolean found = false

println "greeting: ${greeting} (${greeting.class.simpleName})"
println "count: ${count} (${count.class.simpleName})"
println "ratio: ${ratio} (${ratio.class.simpleName})"
println "found: ${found} (${found.class.simpleName})"

// Dynamic reassignment - def variables can change type
println ""
println "--- Dynamic Reassignment ---"
def value = 100
println "value = ${value} (${value.class.simpleName})"
value = "now a string"
println "value = ${value} (${value.class.simpleName})"
value = [1, 2, 3]
println "value = ${value} (${value.class.simpleName})"

With def, Groovy infers the type at runtime and allows reassignment to different types. With explicit types, you get compile-time checks similar to Java. Notice that Groovy auto-boxes primitives — int becomes Integer, double becomes Double.

Strings and GStrings

Groovy distinguishes between regular Java strings (single quotes) and interpolated GStrings (double quotes). This is an important distinction that doesn’t exist in Java.

Create a file named variables_strings.groovy:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// Single-quoted strings are plain java.lang.String
def plain = 'No interpolation here: ${this is literal}'
println plain
println "Type: ${plain.class.simpleName}"

// Double-quoted strings with expressions become GStrings
def lang = "Groovy"
def version = 4.0
def interpolated = "Welcome to ${lang} ${version}"
println interpolated
println "Type: ${interpolated.class.simpleName}"

// Multi-line strings with triple quotes
def multiLine = """
    Name: ${lang}
    Version: ${version}
    JVM Language: Yes
""".stripIndent().trim()
println multiLine

// Slashy strings for regex patterns
def pattern = ~/\d{3}-\d{4}/
println ""
println "Pattern type: ${pattern.class.simpleName}"
println "Matches '555-1234': ${'555-1234' ==~ pattern}"
println "Matches 'hello': ${'hello' ==~ pattern}"

// String methods Groovy adds to java.lang.String
println ""
println "--- Groovy String Methods ---"
def text = "hello groovy world"
println "Capitalize: ${text.capitalize()}"
println "Contains: ${text.contains('groovy')}"
println "Reverse: ${text.reverse()}"
println "Words: ${text.tokenize()}"

Type Conversions

Groovy provides multiple ways to convert between types, from the as keyword to Java-style casting and constructor-based conversion.

Create a file named variables_types.groovy:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// The 'as' keyword for coercion
def numStr = "42"
def num = numStr as int
println "String '${numStr}' as int: ${num} (${num.class.simpleName})"

def pi = 3.14159
def rounded = pi as int
println "Double ${pi} as int: ${rounded} (${rounded.class.simpleName})"

// toInteger(), toDouble(), etc. - Groovy adds these to String
println ""
println "--- Conversion Methods ---"
println "'100'.toInteger(): ${'100'.toInteger()} (${('100'.toInteger()).class.simpleName})"
println "'3.14'.toDouble(): ${'3.14'.toDouble()} (${('3.14'.toDouble()).class.simpleName})"
println "'true'.toBoolean(): ${'true'.toBoolean()}"
println "42.toString(): ${42.toString()} (${42.toString().class.simpleName})"

// BigDecimal and BigInteger - Groovy's default for decimal literals
println ""
println "--- Big Number Types ---"
def bigDec = 1.1
println "1.1 is ${bigDec.class.simpleName}"
def bigInt = 1000000000000000000
println "Large int is ${bigInt.class.simpleName}"

// Explicit BigDecimal arithmetic (avoids floating-point issues)
def price = 19.99
def tax = 0.08
def total = price + (price * tax)
println "Price: ${price}, Tax: ${tax}"
println "Total: ${total} (${total.class.simpleName})"

// Null safety
println ""
println "--- Null Handling ---"
def nullable = null
println "null value: ${nullable}"
println "Safe navigation: ${nullable?.toString()}"
println "Elvis operator: ${nullable ?: 'default value'}"

// Constants with final
println ""
println "--- Constants ---"
final MAX_SIZE = 100
final String APP_NAME = "GroovyApp"
println "MAX_SIZE: ${MAX_SIZE}"
println "APP_NAME: ${APP_NAME}"

Groovy uses BigDecimal for decimal literals by default rather than double, which avoids the floating-point precision issues common in many languages. The safe navigation operator (?.) and Elvis operator (?:) provide elegant null handling.

Running with Docker

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Pull the official image
docker pull groovy:4.0-jdk17-alpine

# Run the variables example
docker run --rm -v $(pwd):/app -w /app groovy:4.0-jdk17-alpine groovy variables.groovy

# Run the strings example
docker run --rm -v $(pwd):/app -w /app groovy:4.0-jdk17-alpine groovy variables_strings.groovy

# Run the type conversions example
docker run --rm -v $(pwd):/app -w /app groovy:4.0-jdk17-alpine groovy variables_types.groovy

Expected Output

Output from variables.groovy:

Language: Groovy
First appeared: 2003
Pi: 3.14159
Active: true

--- Runtime Types ---
name is String
year is Integer
pi is BigDecimal
active is Boolean

--- Explicit Types ---
greeting: Hello from Groovy (String)
count: 42 (Integer)
ratio: 0.75 (Double)
found: false (Boolean)

--- Dynamic Reassignment ---
value = 100 (Integer)
value = now a string (String)
value = [1, 2, 3] (ArrayList)

Output from variables_strings.groovy:

No interpolation here: ${this is literal}
Type: String
Welcome to Groovy 4.0
Type: GStringImpl
Name: Groovy
Version: 4.0
JVM Language: Yes

Pattern type: Pattern
Matches '555-1234': true
Matches 'hello': false

--- Groovy String Methods ---
Capitalize: Hello groovy world
Contains: true
Reverse: dlrow yvoorg olleh
Words: [hello, groovy, world]

Output from variables_types.groovy:

String '42' as int: 42 (Integer)
Double 3.14159 as int: 3 (Integer)

--- Conversion Methods ---
'100'.toInteger(): 100 (Integer)
'3.14'.toDouble(): 3.14 (Double)
'true'.toBoolean(): true
42.toString(): 42 (String)

--- Big Number Types ---
1.1 is BigDecimal
Large int is Long
Price: 19.99, Tax: 0.08
Total: 21.5892 (BigDecimal)

--- Null Handling ---
null value: null
Safe navigation: null
Elvis operator: default value

--- Constants ---
MAX_SIZE: 100
APP_NAME: GroovyApp

Key Concepts

  • def vs explicit types: Use def for dynamic typing and rapid prototyping; use explicit Java types (String, int, double) when you want compile-time safety or documentation
  • Auto-boxing: Groovy automatically wraps primitives in their object equivalents — int becomes Integer, boolean becomes Boolean
  • BigDecimal by default: Decimal literals like 3.14 are BigDecimal, not double, giving you precise arithmetic out of the box
  • Single vs double quotes: Single-quoted strings are plain String; double-quoted strings with ${} expressions become GString — a Groovy-specific interpolated string type
  • as keyword: Groovy’s idiomatic way to convert between types, cleaner than Java-style casting
  • Null safety operators: The safe navigation operator (?.) and Elvis operator (?:) provide concise null handling without verbose if-checks
  • Dynamic reassignment: Variables declared with def can be reassigned to values of completely different types at runtime
  • Java compatibility: Every Java type works in Groovy — you can mix Groovy’s dynamic features with Java’s static types freely

Running Today

All examples can be run using Docker:

docker pull groovy:4.0-jdk17-alpine
Last updated:

Comments

Loading comments...

Leave a Comment

2000 characters remaining