Working with collections is one of the most common tasks in any programming language — whether you're cleaning up data, processing API responses, or building automation scripts. Groovy makes this easier and more expressive with its powerful collection methods, concise syntax, and closure-based operations.
Unlike Java, where filtering and transforming collections often requires verbose loops or streams, Groovy provides a rich toolbox of functions such as find, findAll, collect, groupBy, and more. These methods turn collection processing into readable, declarative code that’s easy to maintain.
In this tutorial, you’ll learn how to:
-
Filter lists and maps using expressive conditions
-
Find single or multiple elements efficiently
-
Transform collections using Groovy’s mapping functions
-
Group, sort, and aggregate data
-
Apply these techniques to real-world scenarios like JSON parsing and data cleanup
By the end, you’ll be able to write cleaner, more idiomatic Groovy code and fully leverage the power of collection methods to simplify your scripts and applications.
Prerequisites
Before diving into Groovy’s powerful collection methods, make sure you have the following setup and baseline knowledge.
What You Need
1. Groovy Installed
You should have Groovy 4.x or later installed on your machine.
To check your version, run:
groovy -version
If you need to install or upgrade, download it from the official Groovy website or use SDKMAN:
sdk install groovy
2. Java Installed (JDK 11 or Later)
Groovy runs on the JVM, so ensure you have at least JDK 11 installed:
java -version
3. A Text Editor or IDE
Any of the following works well:
-
IntelliJ IDEA with Groovy plugin
-
VS Code with Groovy extensions
-
Groovy Console (comes with Groovy)
-
Any text editor + Groovy CLI
How to Run the Code Examples
Throughout this tutorial, you can run Groovy scripts using:
Option 1: Groovy Console
Open the interactive console:
groovyConsole
Paste and execute code instantly.
Option 2: Groovy CLI
Create and run a Groovy script:
groovy script.groovy
Option 3: IntelliJ or VS Code
Create a Groovy project and run .groovy files directly.
Overview of Groovy Collections
Groovy enhances Java’s collection framework with cleaner syntax, additional helper methods, and powerful closure support. Before we dive into filtering and transforming collections, let’s take a quick look at how Groovy collections work and what makes them so convenient.
Groovy Collection Types
Groovy builds on top of standard Java collections, but makes them easier to work with.
1. Lists
Lists are ordered collections and the most commonly used type.
def numbers = [1, 2, 3, 4, 5]
def names = ['Ana', 'Budi', 'Charlie']
Groovy automatically creates a java.util.ArrayList when using [].
2. Maps
Maps store key–value pairs.
def user = [
name: 'Djamware',
role: 'admin',
age : 30
]
Internally, this becomes a java.util.LinkedHashMap.
3. Sets
Sets contain unique elements.
def unique = [1, 2, 2, 3] as Set // => [1, 2, 3]
Literal Syntax Improvements
Groovy allows you to create collections with very clean syntax:
-
Lists →
[] -
Maps →
[:] -
Sets →
[ ... ] as Set -
Ranges →
1..10,'a'..'z'
Ranges can also be used to generate lists:
def rangeList = (1..5).toList() // [1, 2, 3, 4, 5]
Accessing Values
Groovy adds flexible ways to access collection items:
Why Groovy Collections Are Powerful
Groovy collections shine because they work seamlessly with closures. For example, you can:
-
Filter collections with short, readable conditions
-
Transform items using closures
-
Search, group, and aggregate data easily
-
Chain operations in a functional programming style
Here’s a simple example:
def evens = (1..10).findAll { it % 2 == 0 }
println evens // [2, 4, 6, 8, 10]
This expressive syntax is the foundation for everything we’ll cover next.
Filtering Collections
Filtering is one of the most powerful and commonly used features of Groovy collections. Thanks to closures, you can express filtering logic concisely without writing loops or verbose conditions. The primary tool for filtering is the findAll method.
1. Using findAll on Lists
findAll returns all elements that match a given condition.
Example: Filter numbers
def numbers = [1, 2, 3, 4, 5, 6]
def evens = numbers.findAll { it % 2 == 0 }
println evens // [2, 4, 6]
Example: Filter strings
def fruits = ['apple', 'banana', 'avocado', 'blueberry']
def startsWithA = fruits.findAll { it.startsWith('a') }
println startsWithA // [apple, avocado]
2. Filtering Complex Objects
Groovy makes it easy to filter lists of maps or lists of objects.
Example: Filter the list of maps
def users = [
[name: 'Alice', role: 'admin'],
[name: 'Bob', role: 'user'],
[name: 'Charlie', role: 'admin']
]
def admins = users.findAll { it.role == 'admin' }
println admins
// [[name:Alice, role:admin], [name:Charlie, role:admin]]
Example: Filter by multiple conditions
def products = [
[name: 'Laptop', price: 800],
[name: 'Mouse', price: 25],
[name: 'Monitor', price: 150]
]
def expensive = products.findAll { it.price > 100 && it.name.contains('o') }
println expensive
// [[name:Monitor, price:150]]
3. Filtering Maps
findAll also works on maps — returning a new map containing only the entries that meet the condition.
Example: Filter map values
def scores = [
Ana : 90,
Budi: 70,
Cici: 85
]
def highScores = scores.findAll { key, value -> value >= 80 }
println highScores
// [Ana:90, Cici:85]
Example: Filter by key
def filtered = scores.findAll { name, score -> name.startsWith('A') }
println filtered // [Ana:90]
4. Filtering Nested Collections
Groovy handles nested structures elegantly.
Example: Filtering inside lists of lists
def matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
def rowsWithEvenNumbers = matrix.findAll { row ->
row.any { it % 2 == 0 }
}
println rowsWithEvenNumbers
// [[1,2,3], [4,5,6], [7,8,9]]
5. Chaining Filters
You can chain multiple findAll calls for more complex pipelines.
def result = (1..20)
.findAll { it % 2 == 0 }
.findAll { it > 10 }
println result // [12, 14, 16, 18, 20]
Groovy makes filtering collections readable and expressive — no loops, no boilerplate.
Finding Elements
While findAll returns all matching elements. Groovy also provides several methods for finding single elements, checking conditions, and performing quick validations on collections. These methods make your code more expressive and often replace traditional loops and conditionals.
1. Using find to Get the First Match
find returns the first element that satisfies the condition — or null if no element matches.
Example: Find the first even number
def numbers = [1, 3, 6, 7, 10]
def firstEven = numbers.find { it % 2 == 0 }
println firstEven // 6
2. Using any and every
These methods are perfect for quick checks.
any
Returns true if at least one element satisfies the condition.
def names = ['Alex', 'Budi', 'Charlie']
println names.any { it.startsWith('A') } // true
every
Returns true only if all elements match the condition.
println names.every { it.length() > 2 } // true
3. Counting Matches with count
count returns the number of elements matching a condition.
def numbers = [1, 2, 3, 4, 4, 5, 6]
def countEven = numbers.count { it % 2 == 0 }
println countEven // 3
4. Finding in Maps
Just like lists, you can search through maps using key–value closures.
Example: Find the first high score
def scores = [
Ana : 90,
Budi: 70,
Cici: 85
]
def firstHighScore = scores.find { k, v -> v > 80 }
println firstHighScore
// Ana=90
5. Finding in Complex Objects
Example: Find a user by email
def users = [
[name: 'Alice', email: '[email protected]'],
[name: 'Bob', email: '[email protected]'],
[name: 'Charlie', email: '[email protected]']
]
def bob = users.find { it.email == '[email protected]' }
println bob
// [name:Bob, email:[email protected]]
6. Default Values Using the Elvis Operator
Combine find with ?: to provide a fallback value.
def result = users.find { it.name == 'David' } ?: [name: 'Guest']
println result
// [name:Guest]
7. Chaining Find Operations
You can chain find/findAll for expressive filtering + lookup flows.
def firstBigEven = (1..50)
.findAll { it % 2 == 0 }
.find { it > 20 }
println firstBigEven // 22
Transforming Collections
Transformation is one of Groovy’s strongest features. Whether you want to reshape data, modify values, convert maps to lists, or flatten nested structures, Groovy provides a rich set of transformation methods that make these tasks expressive and concise.
The main transformation tools include:
-
collect→ map each element to a new value -
collectEntries→ transform maps into new maps -
collectMany→ flatten and map at the same time -
Type coercion → convert collections into specific types effortlessly
Let’s go through each one with practical examples.
1. Transforming with collect
collect creates a new list where each element is replaced with a transformed value.
Example: Square numbers
def numbers = [1, 2, 3, 4]
def squares = numbers.collect { it * 2 }
println squares // [2, 4, 6, 8]
Example: Extract fields from objects
def users = [
[name: 'Alice', age: 25],
[name: 'Bob', age: 30],
[name: 'Charlie', age: 28]
]
def names = users.collect { it.name }
println names // [Alice, Bob, Charlie]
Example: Convert values to uppercase
def fruits = ['apple', 'banana', 'avocado']
println fruits.collect { it.toUpperCase() }
// [APPLE, BANANA, AVOCADO]
2. Transforming Maps with collectEntries
collectEntries returns a new map, allowing you to transform keys and/or values.
Example: Modify map values
def scores = [
Ana : 90,
Budi: 70
]
def bonusScores = scores.collectEntries { name, score ->
[name, score + 10]
}
println bonusScores
// [Ana:100, Budi:80]
Example: Transform keys and values
def result = scores.collectEntries { name, score ->
[(name.toUpperCase()): score * 2]
}
println result
// [ANA:180, BUDI:140]
3. Flatten and Map with collectMany
collectMany is perfect when each element returns a list or nested structure.
Example: Flatten nested lists
def matrix = [
[1, 2],
[3, 4],
[5, 6]
]
def flat = matrix.collectMany { row -> row }
println flat
// [1, 2, 3, 4, 5, 6]
Example: Transform + flatten
def words = ['hi', 'hello']
def chars = words.collectMany { it.toList() }
println chars
// ['h', 'i', 'h', 'e', 'l', 'l', 'o']
4. Type Coercion for Transformation
Groovy can convert collections into sets, maps, and lists using simple syntax.
Example: Convert list to set
def items = ['a', 'b', 'a', 'c']
def unique = items as Set
println unique // [a, b, c]
Example: Convert list of key-value pairs to map
def pairs = [['a', 1], ['b', 2]]
def map = pairs.collectEntries { [it[0], it[1]] }
println map // [a:1, b:2]
5. Chaining Transformations
Complex transformations become readable pipelines.
Example: Filter → Transform → Aggregate
def result = (1..10)
.findAll { it % 2 == 0 }
.collect { it * 10 }
println result
// [20, 40, 60, 80, 100]
Groovy’s transformation utilities help convert raw data into clean, structured results with minimal code.
Groovy’s Powerful Iteration Methods
Groovy provides several iteration methods that make looping, reducing, and processing collections far more expressive compared to traditional Java loops. These methods work seamlessly with closures, allowing you to write cleaner, functional-style code.
In this section, we’ll explore:
-
eachandeachWithIndex -
inject(Groovy’s version of reduce/fold) -
Chaining iteration operations for cleaner pipelines
1. Iterating with each
each is Groovy’s simplest iteration method. It loops through a collection and executes the closure for each item.
Example: Loop through a list
def numbers = [1, 2, 3]
numbers.each { println it }
// 1
// 2
// 3
Example: Loop through a map
def user = [name: 'Djamware', role: 'admin']
user.each { key, value ->
println "$key = $value"
}
// name = Djamware
// role = admin
2. Iterating with eachWithIndex
Use eachWithIndex when you need the index of each item.
Example: Display list with index
def names = ['Ana', 'Budi', 'Charlie']
names.eachWithIndex { name, index ->
println "$index: $name"
}
// 0: Ana
// 1: Budi
// 2: Charlie
3. Reducing Collections with inject
inject is one of Groovy’s most powerful iteration tools.
It works like reduce in JavaScript or Python — combining all elements into a single value.
Syntax
collection.inject(initialValue) { acc, value -> ... }
Example 1: Sum numbers
def total = [1, 2, 3, 4].inject(0) { acc, val ->
acc + val
}
println total // 10
Example 2: Build a string
def sentence = ['Groovy', 'makes', 'collections', 'fun']
.inject('') { acc, word -> acc + word + ' ' }
.trim()
println sentence
// Groovy makes collections fun
Example 3: Count character frequency
def chars = ['a', 'b', 'a', 'c', 'b']
def freq = chars.inject([:]) { acc, ch ->
acc[ch] = (acc[ch] ?: 0) + 1
acc
}
println freq
// [a:2, b:2, c:1]
4. Chaining Iteration Methods
Groovy allows method chaining for clean, functional-style pipelines.
Example: Even → Square → Sum
def result = (1..10)
.findAll { it % 2 == 0 }
.collect { it * it }
.inject(0) { acc, val -> acc + val }
println result
// 220
5. When to Use Each Method
| Method | Best For |
|---|---|
each |
Simple iteration, logging, printing, side effects |
eachWithIndex |
Iteration when index matters |
inject |
Calculate totals, build strings, aggregate data |
| Chaining methods | Clean data processing pipelines |
Working with Maps
Maps are one of Groovy’s most powerful collection types. They provide fast lookups, flexible key/value handling, and—thanks to Groovy’s closure support—extremely expressive filtering, finding, and transforming capabilities. In this section, you’ll learn how to filter maps, search for entries, transform key/value pairs, and convert maps to other structures.
1. Filtering Map Entries
Just like lists, maps support findAll for filtering. The closure receives both key and value.
Example: Filter values
def scores = [
Ana : 90,
Budi: 70,
Cici: 85,
Dodi: 60
]
def passed = scores.findAll { name, value -> value >= 80 }
println passed
// [Ana:90, Cici:85]
Example: Filter keys
def namesStartingWithC = scores.findAll { name, value ->
name.startsWith('C')
}
println namesStartingWithC
// [Cici:85]
2. Finding Entries in Maps
Use find to retrieve the first matching key-value pair.
Example: Find entry with highest score above 80
def firstHighScore = scores.find { name, value -> value > 80 }
println firstHighScore
// Ana=90
Example: Find entry by custom logic
def shortName = scores.find { name, value -> name.length() <= 4 }
println shortName
// Budi=70
3. Transforming Maps with collectEntries
collectEntries lets you transform keys, values, or both—returning an entirely new map.
Example: Increase all scores
def boosted = scores.collectEntries { name, score ->
[name, score + 5]
}
println boosted
// [Ana:95, Budi:75, Cici:90, Dodi:65]
Example: Convert keys to lowercase
def lowerKeys = scores.collectEntries { name, score ->
[(name.toLowerCase()): score]
}
println lowerKeys
// [ana:90, budi:70, cici:85, dodi:60]
Example: Transform keys and values
def transformed = scores.collectEntries { name, score ->
[(name.reverse()): score * 2]
}
println transformed
// [anA:180, iduB:140, iciC:170, idoD:120]
4. Converting Maps to Lists
Maps can be converted into many forms using Groovy’s expressive syntax.
Example: Convert map values to list
def scoreList = scores.collect { name, score -> score }
println scoreList
// [90, 70, 85, 60]
Example: Convert entries to list of maps
def entryList = scores.collect { name, score ->
[name: name, score: score]
}
println entryList
// [[name:Ana, score:90], [name:Budi, score:70], ...]
Example: Convert map to list of pairs
def pairs = scores.collect { name, score -> [name, score] }
println pairs
// [[Ana,90], [Budi,70], [Cici,85], [Dodi,60]]
5. Sorting Maps
Groovy makes sorting maps easy using closures.
Example: Sort by value
def sortedByScore = scores.sort { key, value -> value }
println sortedByScore
// [Dodi:60, Budi:70, Cici:85, Ana:90]
Example: Sort by key
def sortedByName = scores.sort { key, value -> key }
println sortedByName
// [Ana:90, Budi:70, Cici:85, Dodi:60]
6. Reversing Maps
Maps can be reversed using .reverse().
def reversed = scores.reverse()
println reversed
// [Dodi:60, Cici:85, Budi:70, Ana:90]
7. Merging Maps
Groovy supports easy map merging using the + operator or the spread operator.
Example: Merge two maps
def defaults = [role: 'user', active: true]
def custom = [active: false, email: '[email protected]']
def result = defaults + custom
println result
// [role:user, active:false, email:[email protected]]
8. Map Truthiness
Groovy treats empty maps as false and non-empty maps as true.
def m = [:]
if (!m) println 'Map is empty'
Maps in Groovy are incredibly flexible and expressive thanks to closure-based operations.
Grouping, Sorting, and Aggregation
Groovy makes it extremely easy to group, sort, and aggregate data—tasks that would typically require verbose loops in Java. With concise methods and closure support, you can process complex datasets elegantly.
In this section, you'll learn:
-
How to group collections with
groupBy -
How to sort lists and maps using closures
-
How to compute aggregates like sum, min, max, and averages
Let’s explore these powerful features one by one.
1. Grouping Collections with groupBy
The groupBy method organizes a collection into a map of groups, where each key represents a group name and the value is a list of items in that group.
Example: Group numbers by even/odd
def numbers = (1..10).toList()
def grouped = numbers.groupBy { it % 2 == 0 ? 'even' : 'odd' }
println grouped
// [odd:[1,3,5,7,9], even:[2,4,6,8,10]]
Example: Group objects by property
def users = [
[name: 'Ana', role: 'admin'],
[name: 'Budi', role: 'user'],
[name: 'Cici', role: 'admin'],
[name: 'Dodi', role: 'user']
]
def groupedByRole = users.groupBy { it.role }
println groupedByRole
// [admin:[[name:Ana, role:admin], [name:Cici, role:admin]],
// user:[[name:Budi, role:user], [name:Dodi, role:user]]]
2. Sorting Collections
Groovy supports sorting lists and maps using closures for custom logic.
Sorting Lists
Example: Sort list of numbers
def nums = [5, 1, 7, 2]
println nums.sort()
// [1, 2, 5, 7]
Example: Sort with custom criteria
def fruits = ['apple', 'banana', 'kiwi']
println fruits.sort { it.length() }
// [kiwi, apple, banana]
Sorting Maps
Example: Sort by key
def scores = [Ana: 90, Budi: 70, Cici: 85]
println scores.sort { key, value -> key }
// [Ana:90, Budi:70, Cici:85]
Example: Sort by value
println scores.sort { key, value -> value }
// [Budi:70, Cici:85, Ana:90]
3. Aggregation Functions
Groovy includes several handy methods for summarizing data.
3.1 Summing Values
Example: Sum list of numbers
def total = [1, 2, 3, 4].sum()
println total // 10
Example: Sum using closure
def users = [
[name: 'Ana', age: 25],
[name: 'Budi', age: 30]
]
def totalAge = users.sum { it.age }
println totalAge // 55
3.2 Max and Min
def numbers = [4, 9, 1, 6]
println numbers.max() // 9
println numbers.min() // 1
Max/Min by property
def maxUser = users.max { it.age }
println maxUser
// [name:Budi, age:30]
3.3 Average (Using sum and count)
Groovy doesn’t have a direct avg() method, but it’s easy to compute.
def nums = [10, 20, 30]
def avg = nums.sum() / nums.size()
println avg // 20
4. Combining Grouping + Aggregation
These methods can be chained to build powerful analytics pipelines.
Example: Total score per group
def data = [
[category: 'A', score: 10],
[category: 'B', score: 20],
[category: 'A', score: 30],
[category: 'B', score: 40]
]
def totals = data
.groupBy { it.category }
.collectEntries { cat, items ->
[cat, items.sum { it.score }]
}
println totals
// [A:40, B:60]
Grouping, sorting, and aggregation are essential for transforming data into meaningful insights, and Groovy makes these tasks simple and expressive.
Real-World Examples
Now that you’ve learned Groovy’s powerful filtering, finding, and transforming methods, it’s time to apply them to real-world scenarios. These examples simulate tasks you would commonly perform when processing data from APIs, files, databases, or automation scripts.
This section will cover:
-
Cleaning and transforming JSON data
-
Working with API-like responses
-
Extracting meaningful insights from collections
-
Building functional pipelines (filter → map → reduce)
1. Cleaning and Transforming JSON Data
When dealing with APIs, you often receive raw JSON that needs to be filtered or transformed before use.
Example: Filter active users and extract emails
def json = [
[name: 'Ana', active: true, email: '[email protected]'],
[name: 'Budi', active: false, email: '[email protected]'],
[name: 'Cici', active: true, email: '[email protected]']
]
// 1. Keep only active users
// 2. Transform into list of emails
def emails = json
.findAll { it.active }
.collect { it.email }
println emails
// [[email protected], [email protected]]
This pattern is extremely common when cleaning API responses before passing them into UIs or databases.
2. Transforming API Response Objects
Let’s say an API returns a list of products, but you only need a simplified structure for the frontend.
Example: Map product objects to a lightweight DTO
def products = [
[id: 1, name: 'Laptop', price: 900, stock: 12],
[id: 2, name: 'Mouse', price: 20, stock: 0],
[id: 3, name: 'Monitor', price: 150, stock: 5]
]
def result = products.collect { p ->
[
id : p.id,
name : p.name,
inStock: p.stock > 0
]
}
println result
/* [
[id:1, name:Laptop, inStock:true],
[id:2, name:Mouse, inStock:false],
[id:3, name:Monitor, inStock:true]
] */
A clean, declarative transformation pipeline—ideal for backend-to-frontend data shaping.
3. Data Cleanup Script
If you often parse text files or logs, Groovy’s filtering and transformation methods help clean data quickly.
Example: Remove blanks and normalize strings
def lines = [' Groovy', '', ' ', 'is', ' awesome ']
def cleaned = lines
.findAll { it.trim() } // remove blank lines
.collect { it.trim().toLowerCase() }
println cleaned
// ['groovy', 'is', 'awesome']
Perfect for preparing input before analysis.
4. Analytics: Group + Sum + Sort
Let’s calculate total sales per category and list them from highest to lowest.
def sales = [
[category: 'A', amount: 100],
[category: 'B', amount: 50],
[category: 'A', amount: 200],
[category: 'C', amount: 150]
]
def totals = sales
.groupBy { it.category }
.collectEntries { cat, items ->
[cat, items.sum { it.amount }]
}
.sort { -it.value }
println totals
// [A:300, C:150, B:50]
A powerful analytic pipeline in just a few lines.
5. Extracting Unique Values
You often need unique values from a dataset.
Example: Unique skills from a list of employees
def employees = [
[name:'Ana', skills:['Groovy', 'Java']],
[name:'Budi', skills:['Java', 'SQL']],
[name:'Cici', skills:['Groovy', 'Kotlin']]
]
def uniqueSkills = employees
.collectMany { it.skills }
.toSet()
println uniqueSkills
// [Groovy, Java, SQL, Kotlin]
6. Detecting Inconsistencies
Example: Find incomplete objects
def records = [
[id:1, name:'Ana'],
[id:2],
[id:3, name:'Cici']
]
def invalid = records.findAll { !it.name }
println invalid
// [[id:2]]
Great for data validation tasks.
7. Building Full Pipelines
Finally, here’s a realistic multi-step pipeline:
Scenario:
You receive raw transaction data. You must:
-
Filter only completed transactions
-
Extract the amounts
-
Convert to USD
-
Sum the final results
def transactions = [
[id: 1, status: 'complete', amount: 100, currency: 'EUR'],
[id: 2, status: 'pending', amount: 200, currency: 'EUR'],
[id: 3, status: 'complete', amount: 150, currency: 'EUR']
]
def eurToUsd = 1.1
def totalUsd = transactions
.findAll { it.status == 'complete' }
.collect { it.amount * eurToUsd }
.sum()
println totalUsd
// 275.0
Elegant, readable, and extremely efficient—this is how Groovy shines in real-world data processing.
Best Practices
Groovy’s collection APIs are powerful, expressive, and concise — but with great power comes the need for clarity and maintainability. This section covers practical best practices to help you write clean, efficient, and idiomatic Groovy code.
1. Write Clear and Readable Closures
Avoid overly complex inline closures. Aim for readability.
❌ Hard to read
users.findAll { it.age > 18 && it.active && it.roles.contains('admin') }
✅ More readable
def isEligible = { u -> u.age > 18 && u.active && u.roles.contains('admin') }
def eligibleUsers = users.findAll(isEligible)
Readable closures help your future self—and your team.
2. Use Method Chaining Wisely
Chaining makes code elegant, but too many chained operations can hurt readability.
❌ Over-chained
def result = nums.findAll { it % 2 == 0 }.collect { it * 3 }.findAll { it > 10 }.sum()
✅ Well-structured chain
def result = nums
.findAll { it % 2 == 0 }
.collect { it * 3 }
.findAll { it > 10 }
.sum()
Break long chains into logical steps.
3. Avoid Unnecessary Intermediate Collections
If performance matters, reduce temporary steps.
❌ Creates unnecessary lists
def evens = nums.findAll { it % 2 == 0 }
def doubled = evens.collect { it * 2 }
def total = doubled.sum()
✅ Efficient pipeline
def total = nums
.findAll { it % 2 == 0 }
.collect { it * 2 }
.sum()
4. Prefer collectEntries for Map Transformations
Avoid manually building new maps with loops.
❌ Verbose loop
def newMap = [:]
oldMap.each { k, v -> newMap[k] = v * 2 }
✅ Groovy way
def newMap = oldMap.collectEntries { k, v -> [k, v * 2] }
Cleaner and more idiomatic.
5. Know Map Truthiness
Remember:
-
[:]→ false -
Non-empty map → true
Use this for quick validations.
if (!config) {
println "Configuration is missing!"
}
6. Use Spread Operator for Extracting Values
Groovy’s spread operator makes extracting properties easy.
Instead of:
def names = users.collect { it.name }
Use:
def names = users*.name
It works for nested properties too:
users*.address*.city
7. Use Default Values to Avoid Null Checks
Combine find with the Elvis operator:
def admin = users.find { it.role == 'admin' } ?: [name: 'Guest Admin']
Useful for handling missing or optional data.
8. Prefer Immutable Collections (When Possible)
Mutable structures can cause hidden bugs in large systems.
Use as ImmutableList or copy maps/lists before mutation.
def safeList = [1,2,3].asImmutable()
9. Don’t Overuse Groovy Magic
Groovy allows many shortcuts — but too much “magic” can confuse readers.
Example: prefer clarity over clever one-liners.
❌ Clever but cryptic
nums.findAll{it&1==0}*.toString()*.
✅ Clear and maintainable
nums.findAll { it % 2 == 0 }.collect { it.toString() }
10. Benchmark If Performance Matters
Groovy is expressive but not always the fastest.
When handling large datasets (hundreds of thousands+ entries):
-
Prefer
eachover heavy chaining -
Use
injectcarefully (may be slower for large loops) -
Consider using Java Streams for tight loops
-
Use profiling tools like
GroovyConsole.inspect(List)or JMH
Groovy's collection utilities are incredibly powerful, but following these best practices will keep your code clean, fast, and professional.
Conclusion
Groovy’s collection APIs are one of the language’s strongest features. With expressive syntax, closure-based operations, and a large set of built-in helper methods, Groovy makes filtering, searching, and transforming collections not only simpler—but also more readable and maintainable.
In this tutorial, you learned how to:
-
Filter data using
findAll, even across nested and complex structures -
Find elements efficiently using
find,any,every, andcount -
Transform collections with
collect,collectEntries, andcollectMany -
Iterate cleanly with
each,eachWithIndex, andinject -
Manipulate maps in expressive and idiomatic ways
-
Group, sort, and aggregate your data using powerful built-in operations
-
Apply these techniques to real-world scenarios such as JSON processing, data cleanup, analytics, and pipelines
By mastering these core techniques, you’ll be able to write elegant, concise, and highly maintainable Groovy scripts—perfect for automation, API data handling, backend development, and any task involving lists, maps, or nested structures.
Groovy continues to be a top choice for developers who want the power of the JVM with the flexibility of a dynamic language. With the knowledge from this tutorial, you’re well-equipped to harness that power effectively.
You can find the full source code on our GitHub.
That's just the basics. If you need more deep learning about Groovy and Grails, you can take the following cheap course:
- The Complete Apache Groovy Developer Course
- Groovy Fundamentals For Testers - Step By Step
- Groovy Programming Fundamentals for Java Developers
- The Complete Jenkins DevOps CI/CD Pipeline Bootcamp
- WebServices/API Testing by SoapUI & ReadyAPI - Groovy |30+hr
- Mastering Grails. A Comprehensive Grails Course.
- Intro to web programming with Groovy on Grails
Thanks!
