Learn every way to Groovy add to map operations with 10 tested examples. Put, leftShift, plus operator, and more on Groovy 5.x.
“A map without entries is like a kitchen without ingredients. Knowing how to fill it efficiently is half the battle.”
Kent Beck, Implementation Patterns
Last Updated: March 2026 | Tested on: Groovy 5.x, Java 17+ | Difficulty: Beginner to Intermediate | Reading Time: 16 minutes
Maps are one of the most-used data structures in Groovy, and knowing how to groovy add to map efficiently matters in everyday tasks like building configuration objects, caching lookup tables, or assembling JSON payloads. Groovy doesn’t give you just one way to do it – it gives you about ten, each with different trade-offs.
From the familiar put() method to Groovy-specific operators like << (leftShift) and the + operator, each approach has its own use case and trade-offs. Some mutate the original map, some create a new one, and some only add entries conditionally.
In this tutorial, you’ll see every method to add entries to a Groovy map – with tested code and real output. If you haven’t read it yet, our Groovy Map Tutorial covers the fundamentals of creating and iterating maps. This post goes deeper into adding entries. We’ll also reference Groovy Lists and Groovy Sets where collections overlap.
Table of Contents
What Does Adding to a Map Mean in Groovy?
Adding to a map means inserting a new key-value pair. If the key already exists, most methods will overwrite the existing value. That’s a critical distinction – a map doesn’t allow duplicate keys, so “adding” and “updating” often use the same operations.
According to the official Groovy Collections documentation, Groovy enhances Java’s Map interface with additional operators and GDK methods, making map manipulation far more concise than in plain Java.
Key Points:
put()is the classic Java method – it adds or replaces an entry and returns the old value- Subscript notation (
map[key] = value) is the most idiomatic Groovy approach - Dot notation (
map.key = value) works for string keys that are valid identifiers - The
<<operator adds entries without overwriting existing ones - The
+operator creates a new map with the added entry putAll()merges an entire map or collection of entries at once
Quick Reference Table
| Method | Syntax | Mutates Original? | Overwrites? | Returns |
|---|---|---|---|---|
put() | map.put(key, val) | Yes | Yes | Old value or null |
Subscript [] | map[key] = val | Yes | Yes | The value |
| Dot notation | map.key = val | Yes | Yes | The value |
<< (leftShift) | map << [key: val] | Yes | Yes | The map |
+ operator | map + [key: val] | No (new map) | Yes (in copy) | New map |
putAll() | map.putAll([k:v]) | Yes | Yes | void |
withDefault | map.withDefault{...} | Yes (on access) | No | Wrapped map |
putIfAbsent() | map.putIfAbsent(k,v) | Yes (if missing) | No | Existing or null |
10 Practical Examples
Example 1: Adding with put()
What we’re doing: Using the classic Java put() method to add entries to a map.
Example 1: put() Method
def fruits = [:]
// Add new entries
fruits.put('apple', 1.50)
fruits.put('banana', 0.75)
fruits.put('cherry', 2.25)
println "Map: ${fruits}"
// put() returns the OLD value (null for new keys)
def oldVal = fruits.put('apple', 1.99)
println "Old apple price: ${oldVal}"
println "Updated map: ${fruits}"
Output
Map: [apple:1.50, banana:0.75, cherry:2.25] Old apple price: 1.50 Updated map: [apple:1.99, banana:0.75, cherry:2.25]
What happened here: put() adds an entry and returns the previous value for that key. If the key didn’t exist before, it returns null. When we called put('apple', 1.99) on an existing key, it updated the value and gave us the old one (1.50). This is useful when you need to know what was there before the update.
Example 2: Subscript Notation ([] Assignment)
What we’re doing: Using bracket notation to add and update map entries – the most common Groovy approach.
Example 2: Subscript [] Assignment
def config = [:]
// Add entries using subscript
config['host'] = 'localhost'
config['port'] = 8080
config['debug'] = true
println "Config: ${config}"
// Keys can be variables
def key = 'timeout'
config[key] = 30000
println "With timeout: ${config}"
// Keys can be any type
config[42] = 'the answer'
config[true] = 'boolean key'
println "Mixed keys: ${config}"
Output
Config: [host:localhost, port:8080, debug:true] With timeout: [host:localhost, port:8080, debug:true, timeout:30000] Mixed keys: [host:localhost, port:8080, debug:true, timeout:30000, 42:the answer, true:boolean key]
What happened here: Subscript notation is the most idiomatic way to groovy add to map. It reads naturally, supports variables as keys, and accepts keys of any type – strings, numbers, booleans, even objects. Under the hood, config['host'] = 'localhost' calls putAt(), which delegates to put().
Example 3: Dot Notation
What we’re doing: Adding entries using property-style dot notation.
Example 3: Dot Notation
def user = [:]
// Dot notation - looks like property access
user.name = 'Alice'
user.age = 30
user.email = 'alice@example.com'
println "User: ${user}"
// Reading also works with dot notation
println "Name: ${user.name}"
println "Age: ${user.age}"
// Updating with dot notation
user.age = 31
println "Updated: ${user}"
Output
User: [name:Alice, age:30, email:alice@example.com] Name: Alice Age: 30 Updated: [name:Alice, age:31, email:alice@example.com]
What happened here: Dot notation treats the map like an object with properties. It’s clean and readable, but it only works when the key is a valid Groovy identifier (no spaces, no special characters, doesn’t start with a number). For keys like 'my-key' or '123abc', use subscript notation instead.
Example 4: leftShift Operator (<<)
What we’re doing: Using the << (leftShift) operator to add entries to a map.
Example 4: leftShift Operator <<
def colors = [red: '#FF0000']
// Add a single entry using leftShift
colors << [green: '#00FF00']
println "After <<: ${colors}"
// Chain multiple leftShift operations
colors << [blue: '#0000FF'] << [yellow: '#FFFF00']
println "Chained: ${colors}"
// leftShift with an existing key DOES overwrite
colors << [red: '#CC0000']
println "Overwritten red: ${colors}"
// Add multiple entries at once
colors << [orange: '#FFA500', purple: '#800080']
println "Multiple: ${colors}"
Output
After <<: [red:#FF0000, green:#00FF00] Chained: [red:#FF0000, green:#00FF00, blue:#0000FF, yellow:#FFFF00] Overwritten red: [red:#CC0000, green:#00FF00, blue:#0000FF, yellow:#FFFF00] Multiple: [red:#CC0000, green:#00FF00, blue:#0000FF, yellow:#FFFF00, orange:#FFA500, purple:#800080]
What happened here: The << operator is a nice way to add entries because it returns the map itself, allowing you to chain operations. It mutates the original map and will overwrite existing keys. Internally, it calls putAll() on the right-hand side map. You can also pass multiple entries in a single map literal on the right side.
Example 5: Plus Operator (+)
What we’re doing: Using the + operator to create a new map with additional entries without modifying the original.
Example 5: Plus Operator +
def defaults = [theme: 'light', lang: 'en', fontSize: 14]
// + creates a NEW map - original is untouched
def custom = defaults + [theme: 'dark', fontSize: 18]
println "Defaults: ${defaults}"
println "Custom: ${custom}"
// Combine multiple maps
def overrides = [lang: 'fr']
def extra = [showToolbar: true]
def merged = defaults + overrides + extra
println "Merged: ${merged}"
// += modifies the variable reference (reassignment)
def settings = [a: 1]
settings += [b: 2, c: 3]
println "After +=: ${settings}"
Output
Defaults: [theme:light, lang:en, fontSize:14] Custom: [theme:dark, lang:en, fontSize:18] Merged: [theme:light, lang:fr, fontSize:14, showToolbar:true] After +=: [a:1, b:2, c:3]
What happened here: The + operator is the only method here that does not mutate the original map. It creates a brand-new map with all entries from both sides. When keys overlap, the right-hand map wins. This makes it great for applying overrides to default configurations. Be aware that += looks like mutation, but it actually creates a new map and reassigns the variable.
Example 6: putAll() – Bulk Adding
What we’re doing: Adding multiple entries at once from another map or collection of entries.
Example 6: putAll()
def inventory = [apples: 50, bananas: 30]
// putAll from another map
def newStock = [cherries: 20, dates: 15, elderberry: 10]
inventory.putAll(newStock)
println "After putAll: ${inventory}"
// putAll overwrites existing keys
inventory.putAll([apples: 75, bananas: 40])
println "After overwrite: ${inventory}"
// putAll from a list of MapEntry pairs
def entries = ['figs', 8, 'grapes', 60]
.collate(2)
.collectEntries { [(it[0]): it[1]] }
inventory.putAll(entries)
println "From entries: ${inventory}"
Output
After putAll: [apples:50, bananas:30, cherries:20, dates:15, elderberry:10] After overwrite: [apples:75, bananas:40, cherries:20, dates:15, elderberry:10] From entries: [apples:75, bananas:40, cherries:20, dates:15, elderberry:10, figs:8, grapes:60]
What happened here: putAll() is the standard Java method for merging maps. It takes another Map and copies all entries into the target map, overwriting any duplicates. It returns void, so you can’t chain it. Use it when you have a batch of entries to add and don’t mind overwriting.
Example 7: withDefault – Auto-Populating on Access
What we’re doing: Creating a map that automatically adds default values when you access missing keys.
Example 7: withDefault
// Counter pattern - default to 0
def counter = [:].withDefault { 0 }
def words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']
words.each { word ->
counter[word]++
}
println "Word counts: ${counter}"
// Grouping pattern - default to empty list
def groups = [:].withDefault { [] }
def people = [
[name: 'Alice', dept: 'Engineering'],
[name: 'Bob', dept: 'Marketing'],
[name: 'Charlie', dept: 'Engineering'],
[name: 'Diana', dept: 'Marketing'],
[name: 'Eve', dept: 'Engineering']
]
people.each { p ->
groups[p.dept] << p.name
}
println "Groups: ${groups}"
Output
Word counts: [apple:3, banana:2, cherry:1] Groups: [Engineering:[Alice, Charlie, Eve], Marketing:[Bob, Diana]]
What happened here: withDefault wraps a map so that accessing a nonexistent key automatically creates it with the closure’s return value. In the counter example, every missing key starts at 0, so counter[word]++ works without checking if the key exists first. In the grouping example, missing keys start as empty lists, so we can immediately call << on them. This eliminates boilerplate null-checking code.
Example 8: putIfAbsent – Conditional Adding
What we’re doing: Adding an entry only when the key doesn’t already exist.
Example 8: putIfAbsent
def cache = [greeting: 'Hello', farewell: 'Goodbye']
// putIfAbsent - adds only if key is missing
cache.putIfAbsent('greeting', 'Hi') // key exists, no change
cache.putIfAbsent('welcome', 'Welcome') // key missing, adds it
println "Cache: ${cache}"
// Return value tells you what happened
def result1 = cache.putIfAbsent('farewell', 'Bye')
def result2 = cache.putIfAbsent('thanks', 'Thank you')
println "Existing key returned: ${result1}" // returns existing value
println "New key returned: ${result2}" // returns null
// Practical use: building a cache
def expensiveCompute = { key -> println " Computing ${key}..."; key.toUpperCase() }
def myCache = [:]
['hello', 'world', 'hello', 'groovy', 'world'].each { word ->
myCache.putIfAbsent(word, expensiveCompute(word))
}
println "Final cache: ${myCache}"
Output
Cache: [greeting:Hello, farewell:Goodbye, welcome:Welcome] Existing key returned: Goodbye New key returned: null Computing hello... Computing world... Computing hello... Computing groovy... Computing world... Final cache: [hello:HELLO, world:WORLD, groovy:GROOVY]
What happened here: putIfAbsent() only inserts the entry when the key is not already present. It returns the existing value if the key was found, or null if the entry was newly added. Note that in the cache example, the value expression is still evaluated even when the key exists – for truly lazy computation, use computeIfAbsent() instead (Java 8+).
Example 9: Conditional Adding with Logic
What we’re doing: Adding entries to a map based on conditions and filters.
Example 9: Conditional Adding
def config = [mode: 'production']
// Add only if a condition is met
def debugMode = false
if (debugMode) {
config['logLevel'] = 'DEBUG'
config['verbose'] = true
}
println "No debug: ${config}"
// Ternary-style conditional add
debugMode = true
config['logLevel'] = debugMode ? 'DEBUG' : 'INFO'
println "With level: ${config}"
// Conditionally add from a list of candidates
def candidates = [
[key: 'timeout', value: 5000, enabled: true],
[key: 'retries', value: 3, enabled: true],
[key: 'proxy', value: 'http://proxy', enabled: false],
[key: 'maxConn', value: 100, enabled: true]
]
candidates.findAll { it.enabled }.each { c ->
config[c.key] = c.value
}
println "Filtered: ${config}"
// collectEntries for building maps from collections
def envVars = ['APP_NAME=MyApp', 'APP_PORT=9090', 'APP_ENV=staging']
def envMap = envVars.collectEntries { entry ->
def (k, v) = entry.split('=')
[(k): v]
}
println "Env map: ${envMap}"
Output
No debug: [mode:production] With level: [mode:production, logLevel:DEBUG] Filtered: [mode:production, logLevel:DEBUG, timeout:5000, retries:3, maxConn:100] Env map: [APP_NAME:MyApp, APP_PORT:9090, APP_ENV:staging]
What happened here: Real-world code often needs conditional logic when building maps. The findAll + each pattern filters candidates before adding them. And collectEntries is a powerful Groovy method that transforms any collection into a map – perfect for parsing key-value strings into structured data. For more collection methods, see our Groovy List Tutorial.
Example 10: Adding from Another Map (Merging)
What we’re doing: Combining entries from multiple maps using different merge strategies.
Example 10: Map Merging
def base = [a: 1, b: 2, c: 3]
def updates = [b: 20, c: 30, d: 40]
// Simple merge (updates win)
def merged1 = base + updates
println "Simple merge: ${merged1}"
// Base wins (only add new keys)
def merged2 = updates + base
println "Base wins: ${merged2}"
// Custom merge - keep the larger value
def merged3 = [:]
(base.keySet() + updates.keySet()).each { key ->
def val1 = base[key]
def val2 = updates[key]
if (val1 != null && val2 != null) {
merged3[key] = Math.max(val1, val2)
} else {
merged3[key] = val1 ?: val2
}
}
println "Max merge: ${merged3}"
// Merge with inject (reduce pattern)
def maps = [[x: 1], [y: 2], [z: 3], [x: 10]]
def combined = maps.inject([:]) { result, m -> result + m }
println "Inject merge: ${combined}"
Output
Simple merge: [a:1, b:20, c:30, d:40] Base wins: [b:2, c:3, d:40, a:1] Max merge: [a:1, b:20, c:30, d:40] Inject merge: [x:10, y:2, z:3]
What happened here: Map merging is a common operation. With the + operator, the right-hand map always wins for duplicate keys. Flip the order to give priority to the other map. For custom strategies (like keeping the larger value), you need to iterate and decide per key. The inject pattern is handy for folding a list of maps into one.
Nested Maps and Complex Structures
Adding entries to nested maps requires navigating the structure. Here’s how to handle multi-level maps safely.
Adding to Nested Maps
// Build a nested structure step by step
def app = [:]
app.database = [:]
app.database.host = 'localhost'
app.database.port = 5432
app.database.credentials = [user: 'admin', pass: 'secret']
println "Nested: ${app}"
// Add to existing nested map
app.database.credentials.role = 'superuser'
println "Updated nested: ${app.database.credentials}"
// Safe nested adding with withDefault (auto-creates nested maps)
def deepMap = [:].withDefault { [:].withDefault { [:] } }
deepMap['level1']['level2']['level3'] = 'deep value'
println "Deep: ${deepMap}"
// Practical: building a JSON-like structure
def response = [:]
response.status = 200
response.data = [:]
response.data.users = []
response.data.users << [id: 1, name: 'Alice']
response.data.users << [id: 2, name: 'Bob']
response.meta = [total: 2, page: 1]
println "Response: ${response}"
Output
Nested: [database:[host:localhost, port:5432, credentials:[user:admin, pass:secret]]] Updated nested: [user:admin, pass:secret, role:superuser] Deep: [level1:[level2:[level3:deep value]]] Response: [status:200, data:[users:[[id:1, name:Alice], [id:2, name:Bob]]], meta:[total:2, page:1]]
The withDefault trick is especially useful for deeply nested structures. Without it, you’d need to check and initialize each level manually before adding entries. This pattern is common when building tree structures or parsing hierarchical data.
Immutable and Concurrent Maps
Not all maps allow adding. Immutable maps reject modifications, and concurrent maps handle thread-safe operations.
Immutable and Concurrent Maps
// Immutable map - cannot add entries
def immutable = [name: 'Alice', age: 30].asImmutable()
println "Immutable: ${immutable}"
try {
immutable.put('email', 'alice@example.com')
} catch (UnsupportedOperationException e) {
println "Cannot modify: ${e.message}"
}
// Use + to create a new map from immutable base
def extended = immutable + [email: 'alice@example.com']
println "Extended (new map): ${extended}"
println "Original still: ${immutable}"
// Concurrent map - thread-safe adding
import java.util.concurrent.ConcurrentHashMap
def concurrent = new ConcurrentHashMap()
concurrent.put('counter', 0)
// computeIfAbsent - truly lazy, thread-safe
concurrent.computeIfAbsent('expensive') { key ->
println " Computing value for '${key}'..."
key.toUpperCase()
}
println "Concurrent: ${concurrent}"
// Won't compute again - key already exists
concurrent.computeIfAbsent('expensive') { key ->
println " This won't print"
'SHOULD NOT APPEAR'
}
println "Still: ${concurrent}"
Output
Immutable: [name:Alice, age:30] Cannot modify: null Extended (new map): [name:Alice, age:30, email:alice@example.com] Original still: [name:Alice, age:30] Computing value for 'expensive'... Concurrent: [counter:0, expensive:EXPENSIVE] Still: [counter:0, expensive:EXPENSIVE]
Immutable maps created with asImmutable() throw an exception if you try to add, remove, or update entries. The + operator still works because it creates a new map. For thread-safe code, ConcurrentHashMap gives you computeIfAbsent(), which is truly lazy – the closure only runs if the key is missing. Unlike putIfAbsent(), the value isn’t computed unnecessarily.
Deprecated vs Modern Approach
Old vs Modern Map Adding
// Old way: Verbose Java-style
def oldMap = new java.util.HashMap()
oldMap.put("name", "Alice")
oldMap.put("age", 30)
println "Old style: ${oldMap}"
// Modern way: Groovy map literal + subscript
def newMap = [name: 'Alice', age: 30]
newMap['email'] = 'alice@example.com'
println "Modern: ${newMap}"
// Old way: Manual null-check before adding
def oldCache = [:]
if (!oldCache.containsKey('key1')) {
oldCache.put('key1', 'value1')
}
println "Old cache: ${oldCache}"
// Modern way: putIfAbsent or computeIfAbsent
def newCache = [:]
newCache.putIfAbsent('key1', 'value1')
newCache.computeIfAbsent('key2') { k -> "computed-${k}" }
println "Modern cache: ${newCache}"
Output
Old style: [name:Alice, age:30] Modern: [name:Alice, age:30, email:alice@example.com] Old cache: [key1:value1] Modern cache: [key1:value1, key2:computed-key2]
Migration Note: There’s nothing wrong with
put()– it’s the standard Java API and works fine. But Groovy’s subscript notation, map literals, and operators like<<are more idiomatic. UsecomputeIfAbsent()over manualcontainsKey()checks for cleaner, thread-safe code.
Edge Cases and Best Practices
Best Practices Summary
DO:
- Use subscript notation (
map[key] = value) for general-purpose adding – it’s the most readable - Use
withDefaultwhen building counters, groupings, or nested structures - Use the
+operator when you need an immutable workflow (don’t modify the original) - Use
computeIfAbsent()for lazy, thread-safe cache patterns - Use
collectEntrieswhen transforming collections into maps
DON’T:
- Use GStrings as map keys – they don’t match String keys in lookups
- Use
put()when you don’t need the return value – subscript is cleaner - Forget that
<<andputAll()overwrite existing keys - Assume
+=modifies the map in place – it creates a new map and reassigns
Performance Considerations
Most map operations are O(1) for a HashMap (the default in Groovy). But there are a few things to watch out for:
Performance Tips
// Slow: Using + operator in a loop (creates a new map each time)
def slow() {
def result = [:]
1000.times { i ->
result = result + [(i): "value-${i}"] // new map every iteration!
}
return result.size()
}
// Fast: Using subscript in a loop (mutates in place)
def fast() {
def result = [:]
1000.times { i ->
result[i] = "value-${i}" // O(1) per insert
}
return result.size()
}
// Also fast: Using collectEntries (one allocation)
def alsoFast() {
return (0..999).collectEntries { [(it): "value-${it}"] }.size()
}
println "All produce maps of size: ${fast()}"
Output
All produce maps of size: 1000
The + operator creates a new map on every call. In a loop with 1000 iterations, that’s 1000 new maps created and garbage collected – O(n^2) total copying. Use subscript assignment or collectEntries for bulk operations.
Common Pitfalls
Pitfall 1: GString Keys vs String Keys
GString Key Pitfall
def key = 'name'
def map = [:]
// These create TWO different entries!
map["${key}"] = 'Alice' // GString key
map[key] = 'Bob' // String key
println "Size: ${map.size()}" // 2, not 1!
println "Map: ${map}"
// Fix: always use .toString() on GString keys
def fixedMap = [:]
fixedMap["${key}".toString()] = 'Alice'
fixedMap[key] = 'Bob'
println "Fixed size: ${fixedMap.size()}" // 1
println "Fixed: ${fixedMap}"
Output
Size: 2 Map: [name:Alice, name:Bob] Fixed size: 1 Fixed: [name:Bob]
This is the most common map pitfall in Groovy. A GString and a String with the same content have different hash codes, so they become separate keys in the map. Always convert GStrings to Strings when using them as keys.
Pitfall 2: Variable Key Names in Map Literals
Variable Key Pitfall
def myKey = 'color'
// This does NOT use the variable - key is the string "myKey"
def wrong = [myKey: 'red']
println "Wrong: ${wrong}" // [myKey:red]
// Use parentheses to force variable evaluation
def right = [(myKey): 'red']
println "Right: ${right}" // [color:red]
Output
Wrong: [myKey:red] Right: [color:red]
In Groovy map literals, bare words on the left side of the colon become string keys literally. To use a variable as the key, wrap it in parentheses: [(variable): value]. This is a common source of bugs, especially for developers coming from JavaScript.
Conclusion
We’ve covered every way to groovy add to map – from the basic put() method and subscript notation to operators like << and +, bulk operations with putAll(), conditional adding with putIfAbsent(), and auto-populating maps with withDefault.
The right method depends on your situation. For everyday code, subscript notation (map[key] = value) is the go-to choice. When you need immutability, reach for the + operator. For counters and grouping, withDefault eliminates boilerplate. And for thread-safe caching, computeIfAbsent() is the modern answer.
For a broader look at maps in Groovy, check out our Groovy Map Tutorial. And if you’re working with other collection types, see our guides on Groovy Lists and Groovy Sets.
Summary
- Subscript notation (
map[key] = value) is the most idiomatic way to add entries - The
<<operator mutates the map; the+operator creates a new one withDefaulteliminates null checks for counters, groups, and nested mapsputIfAbsent()andcomputeIfAbsent()handle conditional and lazy adding- Never use GStrings as map keys – convert to String first with
.toString()
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 List Tutorial – All Methods with Examples
Frequently Asked Questions
How do I add a key-value pair to a map in Groovy?
The simplest way is subscript notation: map['key'] = ‘value’. You can also use put(), dot notation (map.key = ‘value’), the leftShift operator (map << [key: 'value']), or the plus operator (newMap = map + [key: 'value']). Subscript notation is the most idiomatic Groovy approach.
What is the difference between << and + for Groovy maps?
The << (leftShift) operator mutates the original map and returns it, allowing chaining. The + (plus) operator creates a brand-new map with the combined entries, leaving the original unchanged. Use << when you want to modify in place, and + when you want immutability.
How do I add to a map only if the key doesn’t exist?
Use putIfAbsent(key, value) to add an entry only when the key is missing. For lazy computation, use computeIfAbsent(key) { closure } which only evaluates the closure if the key doesn’t exist. You can also use withDefault to auto-populate on access.
Can I add entries to an immutable map in Groovy?
No. Calling put(), <<, or subscript assignment on a map created with asImmutable() throws an UnsupportedOperationException. However, you can use the + operator to create a new map that includes the immutable map’s entries plus your additions.
Why does my Groovy map have duplicate keys?
This usually happens when you mix GString keys and String keys. A GString (“${variable}“) and a String (‘text’) have different hash codes even if they contain the same text. Always call .toString() on GString values before using them as map keys to avoid this issue.
Related Posts
Previous in Series: Groovy Map Tutorial – The Complete Guide
Next in Series: Groovy List Tutorial – All Methods with Examples
Related Topics You Might Like:
- Groovy Map Tutorial – The Complete Guide
- Groovy List Tutorial – All Methods with Examples
- Groovy Set – Examples and Best Practices
This post is part of the Groovy & Grails Cookbook series on TechnoScripts.com

No comment