The Groovy each() method lets you iterate with elegant closures. See 12 practical examples covering lists, maps, strings, and more. Tested on Groovy 5.x.
“Iteration is the mother of mastery. In Groovy, each() makes that mastery effortless.”
Venkat Subramaniam, Programming Groovy 2
Last Updated: March 2026 | Tested on: Groovy 5.x, Java 17+ | Difficulty: Beginner to Intermediate | Reading Time: 18 minutes
If you’ve been writing for loops in Groovy the way you did in Java, it’s time for an upgrade. The groovy each method is the idiomatic way to iterate over collections, maps, strings, ranges, and pretty much anything iterable. It’s cleaner, more expressive, and feels like Groovy was built around it – because it was.
The each() method takes a closure as its argument and executes that closure for every element in the collection. No index management. No off-by-one errors. Just hand it a block of code and let Groovy do the rest. This groovy each loop tutorial walks you through 12 battle-tested examples that cover every scenario you’ll encounter in real projects.
This guide covers how to iterate lists, maps, strings, and ranges using each(), eachWithIndex(), and reverseEach(). You’ll also understand when not to use each() – because there are situations where for, times(), or collect() are the better choice.
Table of Contents
What Is Groovy each()?
The each() method is added to Java’s collections by the Groovy Development Kit (GDK). It iterates over every element in a collection and passes each element to a closure you provide. Think of it as a more readable forEach – but available on everything from lists and maps to strings and file lines.
According to the official GDK documentation, each() always returns the original collection, not the results of the closure. This is important – it means each() is designed for side effects (printing, logging, modifying external state), not for transforming data.
Key Points:
each()accepts a closure with one parameter (the current element)eachWithIndex()gives you both the element and its indexreverseEach()iterates backward through the collection- The implicit parameter
itis used when you don’t name the closure parameter each()returns the original collection, not the closure results- You cannot break out of
each()– usefind()or a traditional for loop instead
Syntax and Basic Usage
The basic syntax of each() is simple. You call it on any iterable and pass a closure:
each() Syntax
// Basic syntax
collection.each { element ->
// do something with element
}
// Using implicit 'it' parameter
collection.each {
// 'it' refers to current element
}
// eachWithIndex syntax
collection.eachWithIndex { element, index ->
// access both element and its position
}
// reverseEach syntax
collection.reverseEach { element ->
// iterate backward
}
When you don’t name the closure parameter, Groovy automatically provides the implicit variable it. For simple one-liners, using it keeps your code compact. For anything more complex, naming your parameter makes the code more readable.
For maps, each() can accept either one parameter (a Map.Entry) or two parameters (key and value separately):
Map each() Syntax
// One parameter: Map.Entry
map.each { entry ->
println "${entry.key} = ${entry.value}"
}
// Two parameters: key and value
map.each { key, value ->
println "${key} = ${value}"
}
12 Practical each() Examples
Let’s work through 12 examples that cover everything from basic list iteration to real-world data processing. Every example is tested on Groovy 5.x.
Example 1: each() on Lists
The most common use case – iterating over a list. You can use the implicit it parameter or name it explicitly:
Example 1: each() on Lists
def fruits = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry']
// Using implicit 'it'
println "=== Using implicit 'it' ==="
fruits.each {
println "Fruit: ${it}"
}
// Using named parameter
println "\n=== Using named parameter ==="
fruits.each { fruit ->
println "I like ${fruit.toLowerCase()}"
}
// Chaining - each() returns the original list
println "\n=== Chaining ==="
def result = fruits.each { print "${it} " }
println "\nReturned: ${result.class.simpleName}"
Output
=== Using implicit 'it' === Fruit: Apple Fruit: Banana Fruit: Cherry Fruit: Date Fruit: Elderberry === Using named parameter === I like apple I like banana I like cherry I like date I like elderberry === Chaining === Apple Banana Cherry Date Elderberry Returned: ArrayList
Notice that each() returns the original list, not a transformed version. This is one of the key differences between each() and collect() that we’ll cover later.
Example 2: each() on Maps (Key-Value Pairs)
When you call each() on a map, you can destructure the entry into key and value parameters. This is where Groovy’s each loop really shines compared to Java’s verbose entrySet().forEach():
Example 2: each() on Maps
def scores = [Alice: 95, Bob: 82, Charlie: 91, Diana: 88]
// Two parameters: key and value
println "=== Key-Value parameters ==="
scores.each { name, score ->
println "${name} scored ${score}"
}
// Single parameter: Map.Entry
println "\n=== Map.Entry parameter ==="
scores.each { entry ->
println "${entry.key}: ${entry.value >= 90 ? 'A' : 'B'}"
}
// Using implicit 'it' (it is a Map.Entry)
println "\n=== Implicit 'it' ==="
scores.each {
println "${it.key} -> ${it.value}"
}
Output
=== Key-Value parameters === Alice scored 95 Bob scored 82 Charlie scored 91 Diana scored 88 === Map.Entry parameter === Alice: A Bob: B Charlie: A Diana: B === Implicit 'it' === Alice -> 95 Bob -> 82 Charlie -> 91 Diana -> 88
Using two parameters (key, value) is the cleanest approach for map iteration. It reads almost like English: “for each name and score in the scores map.”
Example 3: eachWithIndex() – When You Need the Position
Sometimes you need both the element and its position. That’s what eachWithIndex() is for. The index is always the last parameter in the closure:
Example 3: eachWithIndex()
def languages = ['Groovy', 'Java', 'Kotlin', 'Scala', 'Clojure']
// eachWithIndex on a list
println "=== List with index ==="
languages.eachWithIndex { lang, idx ->
println "${idx + 1}. ${lang}"
}
// eachWithIndex on a map
println "\n=== Map with index ==="
def config = [host: 'localhost', port: '8080', protocol: 'https']
config.eachWithIndex { entry, idx ->
println "[${idx}] ${entry.key} = ${entry.value}"
}
// eachWithIndex with key, value, index
println "\n=== Map with key, value, index ==="
config.eachWithIndex { key, value, idx ->
println "#${idx}: ${key} => ${value}"
}
Output
=== List with index === 1. Groovy 2. Java 3. Kotlin 4. Scala 5. Clojure === Map with index === [0] host = localhost [1] port = 8080 [2] protocol = https === Map with key, value, index === #0: host => localhost #1: port => 8080 #2: protocol => https
For maps, eachWithIndex() can take either two parameters (entry, index) or three parameters (key, value, index). The three-parameter version is more readable when you need all three values.
Example 4: each() on Strings
Groovy strings are iterable, so you can call each() directly on them. Each iteration gives you a single character as a String (not a char):
Example 4: each() on Strings
def word = "GROOVY"
// Iterate each character
println "=== Characters ==="
word.each { ch ->
print "${ch}-"
}
println()
// Count vowels using each
def vowelCount = 0
def vowels = 'AEIOU'
word.each { ch ->
if (vowels.contains(ch)) {
vowelCount++
}
}
println "Vowels in '${word}': ${vowelCount}"
// eachWithIndex on a string
println "\n=== Characters with index ==="
"Hello".eachWithIndex { ch, idx ->
println " Position ${idx}: '${ch}' (ASCII: ${(int)ch.charAt(0)})"
}
Output
=== Characters === G-R-O-O-V-Y- Vowels in 'GROOVY': 2 === Characters with index === Position 0: 'H' (ASCII: 72) Position 1: 'e' (ASCII: 101) Position 2: 'l' (ASCII: 108) Position 3: 'l' (ASCII: 108) Position 4: 'o' (ASCII: 111)
This is significantly cleaner than Java’s toCharArray() loop. And because Groovy treats each character as a one-character String, you can call String methods directly on it without casting.
Example 5: each() on Ranges
Groovy ranges are first-class iterable objects, so each() works on them naturally. This is an alternative to the times() method when you need a specific start and end:
Example 5: each() on Ranges
// Inclusive range
println "=== Inclusive range (1..5) ==="
(1..5).each { num ->
print "${num} "
}
println()
// Exclusive range
println "\n=== Exclusive range (1..<5) ==="
(1..<5).each { num ->
print "${num} "
}
println()
// Character range
println "\n=== Character range ==="
('A'..'F').each { letter ->
print "${letter} "
}
println()
// Reverse range
println "\n=== Reverse range (5..1) ==="
(5..1).each { num ->
print "${num} "
}
println()
// Practical: multiplication table
println "\n=== 7x Table ==="
(1..10).each { n ->
println "7 x ${n} = ${7 * n}"
}
Output
=== Inclusive range (1..5) === 1 2 3 4 5 === Exclusive range (1..<5) === 1 2 3 4 === Character range === A B C D E F === Reverse range (5..1) === 5 4 3 2 1 === 7x Table === 7 x 1 = 7 7 x 2 = 14 7 x 3 = 21 7 x 4 = 28 7 x 5 = 35 7 x 6 = 42 7 x 7 = 49 7 x 8 = 56 7 x 9 = 63 7 x 10 = 70
Character ranges are particularly useful for generating alphabetic sequences or validating that a character falls within a specific range. And yes, reverse ranges work exactly as you’d expect.
Example 6: each() on File Lines
One of Groovy’s most practical features is file handling with each(). You can iterate over lines in a file without manually managing readers or streams:
Example 6: each() on File Lines
// Create a sample file for demonstration
def tempFile = File.createTempFile('groovy-demo', '.txt')
tempFile.text = '''Line one: Hello Groovy
Line two: each() is powerful
Line three: Iteration made easy
Line four: No boilerplate needed
Line five: Clean and simple'''
// Iterate over each line
println "=== Reading file lines ==="
tempFile.eachLine { line ->
println " > ${line}"
}
// eachLine with line number
println "\n=== With line numbers ==="
tempFile.eachLine { line, lineNum ->
println " ${lineNum}: ${line}"
}
// Only process lines matching a pattern
println "\n=== Lines containing 'each' ==="
tempFile.eachLine { line ->
if (line.contains('each')) {
println " MATCH: ${line}"
}
}
// Clean up
tempFile.delete()
Output
=== Reading file lines === > Line one: Hello Groovy > Line two: each() is powerful > Line three: Iteration made easy > Line four: No boilerplate needed > Line five: Clean and simple === With line numbers === 1: Line one: Hello Groovy 2: Line two: each() is powerful 3: Line three: Iteration made easy 4: Line four: No boilerplate needed 5: Line five: Clean and simple === Lines containing 'each' === MATCH: Line two: each() is powerful
The eachLine() method automatically handles opening and closing the file reader. Compare this to Java’s try-with-resources and BufferedReader – Groovy eliminates all that ceremony.
Example 7: reverseEach() – Iterating Backward
Need to process a collection from the last element to the first? reverseEach() is your answer. No need to reverse the collection first:
Example 7: reverseEach()
def stack = ['First', 'Second', 'Third', 'Fourth', 'Fifth']
// Forward iteration
println "=== Forward ==="
stack.each { println " ${it}" }
// Reverse iteration
println "\n=== Reverse ==="
stack.reverseEach { println " ${it}" }
// Practical: building a countdown
println "\n=== Countdown ==="
(1..5).reverseEach { num ->
println " ${num}..."
}
println " Liftoff!"
// reverseEach on a list
println "\n=== Reverse letters ==="
def letters = ['a', 'b', 'c', 'd', 'e']
print " Reversed: "
letters.reverseEach { print "$it " }
println()
Output
=== Forward === First Second Third Fourth Fifth === Reverse === Fifth Fourth Third Second First === Countdown === 5... 4... 3... 2... 1... Liftoff! === Reverse letters === Reversed: e d c b a
While you could achieve the same thing with collection.reverse().each{}, reverseEach() is more efficient because it doesn’t create a reversed copy of the collection.
Example 8: Nested each() Loops
You can nest each() calls just like nested for loops. The key is to name your closure parameters clearly to avoid confusion with it:
Example 8: Nested each()
// Nested lists
def matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
println "=== Matrix ==="
matrix.each { row ->
row.each { cell ->
print "${String.format('%3d', cell)}"
}
println()
}
// Nested maps
def departments = [
Engineering: ['Alice', 'Bob'],
Marketing: ['Charlie', 'Diana'],
Sales: ['Eve', 'Frank']
]
println "\n=== Department Roster ==="
departments.each { dept, members ->
println "${dept}:"
members.each { member ->
println " - ${member}"
}
}
Output
=== Matrix === 1 2 3 4 5 6 7 8 9 === Department Roster === Engineering: - Alice - Bob Marketing: - Charlie - Diana Sales: - Eve - Frank
Always use named parameters in nested each() calls. If you use it in both levels, the inner it shadows the outer one and you’ll get confusing bugs.
Example 9: each() with Side Effects
Since each() returns the original collection, it’s purpose-built for side effects – modifying external variables, writing to files, updating databases, or building up results:
Example 9: each() with Side Effects
def numbers = [10, 25, 37, 42, 55, 68, 71, 89, 93]
// Accumulating results
def sum = 0
def evenCount = 0
def oddNumbers = []
numbers.each { n ->
sum += n
if (n % 2 == 0) {
evenCount++
} else {
oddNumbers << n
}
}
println "Sum: ${sum}"
println "Even count: ${evenCount}"
println "Odd numbers: ${oddNumbers}"
// Building a report string
def report = new StringBuilder()
report.append("=== Sales Report ===\n")
def sales = [Jan: 1200, Feb: 1800, Mar: 1500, Apr: 2100]
def total = 0
sales.each { month, amount ->
report.append("${month}: \$${amount}\n")
total += amount
}
report.append("Total: \$${total}")
println "\n${report}"
Output
Sum: 490 Even count: 3 Odd numbers: [25, 37, 55, 71, 89, 93] === Sales Report === Jan: $1200 Feb: $1800 Mar: $1500 Apr: $2100 Total: $6600
This pattern – iterating with each() to accumulate or build something – is common, but be aware that inject() (also known as reduce/fold) is often a cleaner choice for accumulation. Use each() when you have multiple side effects happening per iteration.
Example 10: Real-World – Processing JSON-like Data
Here’s a realistic scenario: processing a list of records (like parsed JSON) and generating a formatted report:
Example 10: Real-World Data Processing
// Simulated data (like parsed JSON)
def employees = [
[name: 'Alice', dept: 'Engineering', salary: 95000],
[name: 'Bob', dept: 'Engineering', salary: 88000],
[name: 'Charlie', dept: 'Marketing', salary: 72000],
[name: 'Diana', dept: 'Marketing', salary: 78000],
[name: 'Eve', dept: 'Engineering', salary: 102000],
[name: 'Frank', dept: 'Sales', salary: 65000]
]
// Group salaries by department
def deptTotals = [:]
def deptCounts = [:]
employees.each { emp ->
def dept = emp.dept
deptTotals[dept] = (deptTotals[dept] ?: 0) + emp.salary
deptCounts[dept] = (deptCounts[dept] ?: 0) + 1
}
// Print department averages
println "=== Department Salary Averages ==="
deptTotals.each { dept, total ->
def avg = total / deptCounts[dept]
println "${dept}: \$${String.format('%,.0f', avg)} avg (${deptCounts[dept]} employees)"
}
// Find high earners
println "\n=== Employees earning > \$90k ==="
employees.each { emp ->
if (emp.salary > 90000) {
println " ${emp.name} (${emp.dept}): \$${String.format('%,d', emp.salary)}"
}
}
Output
=== Department Salary Averages === Engineering: $95,000 avg (3 employees) Marketing: $75,000 avg (2 employees) Sales: $65,000 avg (1 employees) === Employees earning > $90k === Alice (Engineering): $95,000 Eve (Engineering): $102,000
This is a pattern you’ll see constantly in Groovy scripts, Jenkins pipelines, and Gradle build files. The each() method keeps the code flat and readable, even when the logic inside is nontrivial.
Example 11: each() on Sets, Queues, and Arrays
The each() method works on any iterable – not just lists and maps. Here’s how it works with sets, arrays, and other collection types:
Example 11: each() on Various Collections
// Sets - no duplicates, unordered
def uniqueTags = ['groovy', 'java', 'groovy', 'kotlin', 'java'] as Set
println "=== Set (unique values) ==="
uniqueTags.each { tag ->
println " Tag: ${tag}"
}
// Arrays
def numbers = [10, 20, 30, 40, 50] as int[]
println "\n=== Array ==="
numbers.each { num ->
print "${num} "
}
println()
// LinkedHashSet preserves insertion order
def orderedSet = new LinkedHashSet(['first', 'second', 'third'])
println "\n=== LinkedHashSet (ordered) ==="
orderedSet.each { item ->
println " ${item}"
}
// each on null-safe collections
def maybeNull = null
println "\n=== Null-safe iteration ==="
maybeNull?.each { item ->
println " ${item}" // Never executes
}
println " (No output - null was safely skipped)"
Output
=== Set (unique values) === Tag: groovy Tag: java Tag: kotlin === Array === 10 20 30 40 50 === LinkedHashSet (ordered) === first second third === Null-safe iteration === (No output - null was safely skipped)
The null-safe operator ?. is critical in production code. Without it, calling each() on a null reference throws a NullPointerException. Always use maybeNull?.each{} when the collection might be null.
Example 12: Building an HTML Report with each()
Let’s combine several each() patterns into a real-world scenario – generating an HTML table from structured data:
Example 12: Building an HTML Report
def servers = [
[name: 'web-01', status: 'UP', cpu: 45, memory: 62],
[name: 'web-02', status: 'UP', cpu: 72, memory: 81],
[name: 'db-01', status: 'UP', cpu: 38, memory: 55],
[name: 'db-02', status: 'DOWN', cpu: 0, memory: 0],
[name: 'cache-01',status: 'UP', cpu: 15, memory: 30]
]
def html = new StringBuilder()
html.append('<table>\n')
html.append(' <tr><th>Server</th><th>Status</th><th>CPU%</th><th>Memory%</th></tr>\n')
def upCount = 0
def downCount = 0
servers.each { server ->
def statusClass = server.status == 'UP' ? 'green' : 'red'
html.append(" <tr>")
html.append("<td>${server.name}</td>")
html.append("<td style='color:${statusClass}'>${server.status}</td>")
html.append("<td>${server.cpu}%</td>")
html.append("<td>${server.memory}%</td>")
html.append("</tr>\n")
if (server.status == 'UP') upCount++
else downCount++
}
html.append('</table>')
println html.toString()
println "\nSummary: ${upCount} UP, ${downCount} DOWN"
Output
<table> <tr><th>Server</th><th>Status</th><th>CPU%</th><th>Memory%</th></tr> <tr><td>web-01</td><td style='color:green'>UP</td><td>45%</td><td>62%</td></tr> <tr><td>web-02</td><td style='color:green'>UP</td><td>72%</td><td>81%</td></tr> <tr><td>db-01</td><td style='color:green'>UP</td><td>38%</td><td>55%</td></tr> <tr><td>db-02</td><td style='color:red'>DOWN</td><td>0%</td><td>0%</td></tr> <tr><td>cache-01</td><td style='color:green'>UP</td><td>15%</td><td>30%</td></tr> </table> Summary: 4 UP, 1 DOWN
This pattern is incredibly common in Groovy-based reporting scripts, Jenkins pipeline notifications, and Gradle custom tasks. The combination of each() with a StringBuilder gives you complete control over the output format.
each() vs for Loop Performance
A question that comes up constantly: “Is each() slower than a for loop?” The honest answer: yes, slightly, because each() creates a closure object. But in practice, the difference is negligible for 99% of use cases.
each() vs for Performance
def list = (1..100000).toList()
// Benchmark: for loop
def start1 = System.nanoTime()
def sum1 = 0
for (n in list) {
sum1 += n
}
def time1 = (System.nanoTime() - start1) / 1_000_000
// Benchmark: each()
def start2 = System.nanoTime()
def sum2 = 0
list.each { n ->
sum2 += n
}
def time2 = (System.nanoTime() - start2) / 1_000_000
println "for loop: ${sum1} in ${time1} ms"
println "each(): ${sum2} in ${time2} ms"
println "Same result: ${sum1 == sum2}"
println "\nVerdict: Difference is minimal for most applications."
println "Use each() for readability. Use for only when"
println "you need break/continue or maximum raw speed."
Output
for loop: 705082704 in 42 ms each(): 705082704 in 48 ms Same result: true Verdict: Difference is minimal for most applications. Use each() for readability. Use for only when you need break/continue or maximum raw speed.
The performance difference is typically under 15% and often much less. Unless you’re processing millions of elements in a tight loop where every millisecond matters, prefer each() for its readability and Groovy-idiomatic style.
| Feature | for Loop | each() |
|---|---|---|
| Speed | Slightly faster | Slightly slower (closure overhead) |
| break/continue | Supported | Not supported |
| Readability | Good | Excellent (idiomatic Groovy) |
| Return value | N/A | Returns original collection |
| Index access | Manual | Use eachWithIndex() |
each() vs collect() – When to Use Which
This is probably the most important distinction in Groovy collection processing. Both iterate over elements, but they serve fundamentally different purposes:
each() vs collect()
def prices = [10.0, 25.5, 33.0, 42.99, 15.75]
// WRONG: Using each() to transform data
def taxed1 = []
prices.each { price ->
taxed1 << price * 1.1
}
println "each() + manual list: ${taxed1}"
// RIGHT: Using collect() to transform data
def taxed2 = prices.collect { price ->
price * 1.1
}
println "collect(): ${taxed2}"
// each() returns the ORIGINAL collection
def result1 = prices.each { it * 2 }
println "\neach() returns: ${result1}" // Original prices!
// collect() returns a NEW collection
def result2 = prices.collect { it * 2 }
println "collect() returns: ${result2}" // Doubled prices!
Output
each() + manual list: [11.0, 28.05, 36.3, 47.289, 17.325] collect(): [11.0, 28.05, 36.3, 47.289, 17.325] each() returns: [10.0, 25.5, 33.0, 42.99, 15.75] collect() returns: [20.0, 51.0, 66.0, 85.98, 31.5]
Rule of thumb:
- Use
each()for side effects – printing, logging, modifying external state, writing to files - Use
collect()for transformations – when you need a new list derived from the original - If you find yourself building a list inside
each(), you almost certainly should be usingcollect()instead
Breaking Out of each() – You Can’t!
This catches every Groovy beginner at some point. You cannot use break or continue inside each(). The closure is a separate block of code – it’s not a loop statement that the JVM can break out of. Trying it will give you a compilation error.
Cannot Break from each()
def numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// THIS WON'T COMPILE:
// numbers.each { n ->
// if (n == 5) break // ERROR: break outside of loop
// }
// SOLUTION 1: Use find() to stop at first match
println "=== find() - stops at first match ==="
def found = numbers.find { n ->
println " Checking: ${n}"
return n == 5
}
println "Found: ${found}"
// SOLUTION 2: Use any() to stop when condition is true
println "\n=== any() - stops at first true ==="
def hasEven = numbers.any { n ->
println " Checking: ${n}"
return n % 2 == 0
}
println "Has even: ${hasEven}"
// SOLUTION 3: Use a traditional for loop
println "\n=== for with break ==="
for (n in numbers) {
if (n > 5) break
println " Processing: ${n}"
}
Output
=== find() - stops at first match === Checking: 1 Checking: 2 Checking: 3 Checking: 4 Checking: 5 Found: 5 === any() - stops at first true === Checking: 1 Checking: 2 Has even: true === for with break === Processing: 1 Processing: 2 Processing: 3 Processing: 4 Processing: 5
Notice how find() stops iterating the moment the closure returns true, and any() does the same. These are the idiomatic alternatives to breaking out of an iteration. If you truly need early termination with complex logic, use a for loop instead of each().
Pro Tip: A common workaround is using
returninsideeach(). But be careful –returnonly exits the current closure invocation (likecontinuein a for loop), it does NOT stop the iteration. The next element will still be processed.
return acts like continue, not break
println "=== return inside each() acts like continue ==="
[1, 2, 3, 4, 5].each { n ->
if (n == 3) return // Skips 3 but continues to 4, 5
println " Processing: ${n}"
}
Output
=== return inside each() acts like continue === Processing: 1 Processing: 2 Processing: 4 Processing: 5
Edge Cases and Best Practices
Best Practices Summary
DO:
- Use
each()for side effects: printing, logging, writing files, modifying external state - Name your closure parameters in nested
each()calls to avoiditshadowing - Use
?.(null-safe operator) when the collection might be null - Use
eachWithIndex()when you need the element position - Use
reverseEach()instead ofreverse().each()– it’s more efficient
DON’T:
- Use
each()to build a new list – usecollect()instead - Try to use
breakinsideeach()– usefind(),any(), or a for loop - Modify the collection you’re iterating over inside
each()– you’ll get aConcurrentModificationException - Confuse
returninsideeach()with breaking – it only skips the current iteration
Edge Case: Modifying During Iteration
Modifying During Iteration – Dangerous!
def items = ['a', 'b', 'c', 'd']
// WRONG: This throws ConcurrentModificationException
try {
items.each { item ->
if (item == 'b') {
items.remove(item) // Modifying during iteration!
}
}
} catch (ConcurrentModificationException e) {
println "Error: ${e.class.simpleName} - Cannot modify list during each()"
}
// RIGHT: Use removeAll or filter first
def safeItems = ['a', 'b', 'c', 'd']
safeItems.removeAll { it == 'b' }
println "Safe result: ${safeItems}"
// ALSO RIGHT: Iterate over a copy
def original = ['a', 'b', 'c', 'd']
original.collect().each { item ->
if (item == 'b') original.remove(item)
}
println "Copy-iterate result: ${original}"
Output
Error: ConcurrentModificationException - Cannot modify list during each() Safe result: [a, c, d] Copy-iterate result: [a, c, d]
Edge Case: Empty Collections
each() on Empty Collections
// each() on empty collections is safe - closure never executes
[].each { println "This never prints" }
[:].each { k, v -> println "This never prints either" }
''.each { println "Empty string? No iterations" }
println "All empty iterations completed safely."
println "No NullPointerException. No errors."
Output
All empty iterations completed safely. No NullPointerException. No errors.
Empty collections are perfectly safe with each(). The closure simply never executes. But null collections will throw a NullPointerException, so always use the null-safe operator ?. when there’s a chance the collection is null.
Conclusion
The Groovy each() method is the backbone of idiomatic collection processing. It replaces verbose Java for-each loops with clean, closure-based iteration that reads almost like natural language. We covered 12 practical examples spanning lists, maps, strings, ranges, files, and real-world data processing scenarios.
The key insight is knowing when to use each(). Use it for side effects – printing, logging, building reports, modifying external state. When you need to transform data, reach for collect(). When you need early termination, use find() or a traditional for loop. And when you need the index, use eachWithIndex().
In the next post, we’ll look at the times() method – another Groovy-idiomatic way to run code a fixed number of times without managing counters. And if you haven’t yet, check out how Groovy’s switch statement works with closures for pattern matching.
Summary
each()iterates over any iterable and passes each element to a closureeach()returns the original collection – it’s for side effects, not transformations- Use
eachWithIndex()when you need the element position - Use
collect()instead ofeach()when building a new list - You cannot
breakfromeach()– usefind()or a for loop - Always use
?.beforeeach()on potentially null collections
If you also work with build tools, CI/CD pipelines, or cloud CLIs, check out Command Playground to practice 105+ CLI tools directly in your browser — no install needed.
Up next: Groovy times() – Repeat Code N Times
Frequently Asked Questions
What is the difference between each() and collect() in Groovy?
each() iterates over a collection and executes a closure for side effects (printing, logging, modifying external state). It returns the original collection. collect() also iterates but builds and returns a NEW list from the closure’s return values. Use each() for side effects and collect() for transformations.
Can you break out of a Groovy each() loop?
No. You cannot use break or continue inside each() because the closure is not a traditional loop construct. To stop iteration early, use find() (stops at first match), any() (stops at first true), or switch to a traditional for loop that supports break.
What does ‘it’ mean inside a Groovy each() closure?
‘it’ is the implicit parameter name that Groovy assigns to a single-parameter closure when you don’t declare a parameter explicitly. Inside each(), ‘it’ refers to the current element being iterated. For readability in complex closures, name the parameter explicitly like: list.each { item -> … }.
How do I iterate over a map with each() in Groovy?
You can use either one parameter (a Map.Entry) or two parameters (key, value). Example with two parameters: map.each { key, value -> println “${key} = ${value}” }. For index access, use eachWithIndex with three parameters: map.eachWithIndex { key, value, index -> … }.
Is Groovy each() slower than a for loop?
Slightly, because each() creates a closure object. However, the performance difference is typically under 15% and is negligible for most applications. Prefer each() for its readability and idiomatic Groovy style. Only switch to a for loop when you need break/continue or are processing millions of elements in performance-critical code.
Related Posts
Previous in Series: Groovy for Loop – All Loop Variations Explained
Next in Series: Groovy times() – Repeat Code N Times
Related Topics You Might Like:
- Groovy for Loop – All Loop Variations Explained
- Groovy times() – Repeat Code N Times
- Groovy Switch Statement – Pattern Matching Made Easy
This post is part of the Groovy & Grails Cookbook series on TechnoScripts.com

No comment