Working with Collections in Groovy
Groovy enriches Java's List, Map, and Set with native syntax and dozens of extra methods added via its GDK (Groovy Development Kit) extensions to Collection, so [1, 2, 3] is a real java.util.ArrayList, [a: 1, b: 2] is a LinkedHashMap, and both come with methods like collect, find, findAll, each, inject, and groupBy that let you transform data declaratively instead of writing manual loops.
Cricket analogy: Groovy's [1,2,3].findAll { it > 1 } is like a scorer instantly filtering a season's scorecards down to only the innings where a batter passed fifty, instead of a scout manually flipping through every single scorecard by hand.
List and Map Literals
Groovy's list literal [10, 20, 30] and map literal [name: 'Ada', lang: 'Groovy'] remove the boilerplate of new ArrayList() and new HashMap() plus repeated .put() calls, and because a map literal preserves insertion order by default (backed by LinkedHashMap), iterating it later reproduces the order you wrote the keys in - a subtlety that trips people coming from plain Java's unordered HashMap.
Cricket analogy: A Groovy map literal [opener: 'Rohit', keeper: 'Pant'] preserving insertion order is like a team sheet pinned in the dressing room that lists batting positions in the exact order the captain wrote them, not shuffled alphabetically by the board.
Functional-Style Iteration
Methods like each, collect, find, findAll, and inject let you replace explicit for-loops with expressive one-liners: numbers.findAll { it % 2 == 0 }.collect { it * it } filters then transforms in a readable pipeline, and inject (Groovy's reduce/fold) accumulates a single result across a collection, e.g. numbers.inject(0) { acc, n -> acc + n } sums a list without a mutable loop counter.
Cricket analogy: deliveries.findAll { it.isWicket }.collect { it.batter } is like a highlights editor filtering an entire innings down to just the wicket-taking balls and then pulling out only the dismissed batters' names for the graphic.
def numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def evenSquares = numbers.findAll { it % 2 == 0 }
.collect { it * it }
println evenSquares // [4, 16, 36, 64, 100]
def total = numbers.inject(0) { acc, n -> acc + n }
println total // 55
def people = [[name: 'Ada', dept: 'Eng'], [name: 'Grace', dept: 'Eng'], [name: 'Linus', dept: 'Ops']]
def byDept = people.groupBy { it.dept }
println byDept.keySet() // [Eng, Ops]
println people*.name // [Ada, Grace, Linus]
println (1..5).collect { it * it } // range used directly as a collection
Beyond findAll/collect/inject, the GDK adds convenience methods directly onto collections without any import: numbers.sum(), numbers.max(), numbers.min(), and numbers.sort() all work out of the box on a plain List, which in Java would require either a loop or an explicit java.util.stream.Collectors pipeline.
Ranges and Spread Operator
Groovy ranges like 1..10 or 'a'..'e' are first-class objects usable directly in for-loops, switch statements, and as list-like collections, while the spread operator *. (e.g., people*.name) calls a method or accesses a property across every element of a collection at once, returning a list of results without writing an explicit collect closure.
Cricket analogy: The spread operator in overs*.runs is like an analyst pulling the runs conceded from every single over of a bowling spell in one glance, instead of checking each over's tally individually.
- Groovy list literals [1,2,3] are real java.util.ArrayList instances; map literals [k: v] are LinkedHashMap instances by default.
- Map literals preserve insertion order because they're backed by LinkedHashMap.
- GDK adds methods like each, collect, find, findAll, inject, and groupBy directly onto Java's Collection and Map.
- collect transforms each element; findAll filters; inject folds/reduces a collection to a single accumulated value.
- Ranges like 1..10 are first-class objects usable in loops, switch statements, and as list-like collections.
- The spread operator *. calls a method or reads a property across every element of a collection at once.
- groupBy partitions a collection into a Map keyed by the closure's return value.
Practice what you learned
1. What Java class does a Groovy map literal like [name: 'Ada'] instantiate by default?
2. Which GDK method reduces a collection to a single accumulated value?
3. What does numbers.findAll { it % 2 == 0 } return?
4. What does the spread operator do in people*.name?
5. What is the key difference between a Groovy map literal and a plain java.util.HashMap regarding iteration order?
Was this page helpful?
You May Also Like
Closures in Groovy
How Groovy's first-class Closure type captures its defining scope, and how owner, delegate, and resolveStrategy power Groovy's DSL syntax.
Operators and Truth in Groovy
Groovy's safe navigation, Elvis, and spaceship operators, operator overloading, and the rules of Groovy Truth for evaluating objects in boolean contexts.
Optional Typing in Groovy
How Groovy lets you mix def (dynamic) and explicit static types, and how @TypeChecked and @CompileStatic add compile-time safety and performance.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics