Control Flow in Groovy
Master conditionals, loops, and switch statements in Groovy with practical, Docker-ready examples covering if/else, ranges, the Elvis operator, and closure-based iteration
Introduction
Control flow is what gives a program its decision-making power—the ability to choose between paths, repeat work, and react to data. Groovy inherits the familiar control structures of Java (if/else, for, while, switch) but layers on dynamic, expressive features that make code shorter and more readable.
As a multi-paradigm language that blends object-oriented, functional, imperative, and scripting styles, Groovy gives you more than one way to express the same logic. You can write a classic C-style for loop, or you can iterate with a closure using each and times. You can write a verbose if/else chain, or collapse a null check into a single Elvis operator (?:). Groovy’s switch statement is also far more powerful than Java’s, matching on ranges, types, lists, and even regular expressions.
A key Groovy concept that shapes control flow is Groovy truth: any value can be evaluated as a boolean. Empty strings, empty collections, zero, and null are all “falsy,” while non-empty and non-zero values are “truthy.” This makes conditionals concise and idiomatic.
In this tutorial you’ll learn how to make decisions with conditionals, repeat work with loops, branch with the enhanced switch, and iterate the Groovy way with closures—all runnable in Docker without installing anything locally.
Conditionals: if, else, ternary, and Elvis
Groovy’s if/else works exactly like Java’s, but Groovy adds the ternary operator for short expressions and the Elvis operator (?:) for concise defaulting. The safe navigation operator (?.) lets you call methods on potentially-null objects without a NullPointerException.
Create a file named conditionals.groovy:
| |
Here temperature is 30, so the first condition fails but temperature >= 25 succeeds. The Elvis operator shines when defaulting: because an empty string is falsy in Groovy, username ?: "Anonymous" yields the fallback. The safe navigation operator returns null rather than crashing when user is null.
The Enhanced switch Statement
Groovy’s switch is one of its standout features. Unlike Java’s traditional switch, which only matched constants, Groovy matches using the isCase() method. This means a case can be a value, a range (1..9), a type (String), a list, or a regular expression pattern. Case order matters—the first match wins—so put more specific patterns first.
Create a file named switch_demo.groovy:
| |
The classify function uses ranges: 1..9 matches any single digit, 10..99 any two-digit number. The describe function shows off type matching (case String, case Integer) and regex matching (case ~/\d{3}-\d{4}/). Note that the regex case comes before case String—since '555-1234' is also a String, the order ensures the phone-number pattern wins.
Loops: for, while, and ranges
Groovy supports the classic C-style for loop, the for-in loop over ranges and collections, and the while loop. Ranges (5..1) are first-class objects and can even count downward.
Create a file named loops.groovy:
| |
The range 5..1 counts down because Groovy detects the start is greater than the end. The for-in loop iterates cleanly over the languages list without index bookkeeping, while the while loop and the C-style for show the more traditional imperative forms still work.
Closure-Based Iteration and Loop Control
The most idiomatic Groovy way to iterate is with closures—small blocks of code passed to methods like each, eachWithIndex, and times. These read naturally and avoid off-by-one errors. For traditional loops, break exits early and continue skips to the next iteration.
Create a file named iteration.groovy:
| |
4.times runs the closure with i from 0 to 3. each and eachWithIndex iterate over collections with a closure parameter. Note that break and continue work in the classic for/while loops but not inside each/times closures—to exit a closure-based iteration early, you return from the closure (which skips to the next element) or use a different method like find.
Running with Docker
Docker lets you run all four examples consistently without installing Groovy locally.
| |
On Windows PowerShell, replace $(pwd) with ${PWD}.
Expected Output
Running conditionals.groovy:
It's a warm day.
Result: Pass
User: Anonymous
Name length: null
Running switch_demo.groovy:
7 is a single digit
15 is a double digit
150 is a large number
hello is a String of length 5
42 is an Integer worth 42
555-1234 is a phone number
Running loops.groovy:
Countdown: 5 4 3 2 1
JVM language: Groovy
JVM language: Java
JVM language: Kotlin
5! = 120
Powers of 2: 1 2 4 8 16
Running iteration.groovy:
Squares: 0 1 4 9
Value: 10
Value: 20
Value: 30
0: a
1: b
2: c
Evens under 10: 0 2 4 6 8
First multiple of 7: 7
Key Concepts
- Groovy truth: Any value can be evaluated as a boolean. Empty strings, empty collections, zero, and
nullare falsy; everything else is truthy. This powers concise conditionals and the Elvis operator. - Elvis operator (
?:): A shorthand for “use this value, or a default if it’s falsy”—name ?: "Anonymous"replaces a verboseif/else. - Safe navigation (
?.): Calls a method only if the object is non-null, returningnullinstead of throwing aNullPointerException. - Powerful switch: Groovy’s
switchmatches on ranges, types, lists, and regex patterns viaisCase(), not just constants. Order your cases from most specific to least specific. - First-class ranges: Expressions like
1..9and5..1are real objects you can loop over, match against, or count downward with. - Closure-based iteration:
each,eachWithIndex, andtimesare the idiomatic Groovy way to iterate, reading more naturally than index-based loops. - break/continue caveat: These work in
forandwhileloops but not insideeach/timesclosures—usereturnto skip an element in a closure instead.
Running Today
All examples can be run using Docker:
docker pull groovy:4.0-jdk17-alpine
Comments
Loading comments...
Leave a Comment