Using Strings as Keys in Hash Maps

Here is a short summary of the official documentation on strings in Groovy

Groovy has two different classes representing a string:

  • java.lang.String 
  • groovy.lang.GString (also called interpolated string in other programming languages)

The difference is that if you instantiate the string with an interpolated expression, you automatically create a GString instance.

var s = "Groovy"				// normal String
assert s instanceof String
var gs = "This is ${s}"			// interpolated expression creates a GString
assert gs instanceof GString

There are couple of things you need to be aware of when using GStrings:

  • GString is automatically converted to String whenever it is passed as a parameter to a method explicitly accepting String.
  • When a method accepts Object, no conversion takes place.
  • GString and String do not have the same hashCode.

Given these three points, using GString as a key in a hash map is quite tricky. Look at the following example:

def map = [:]
def id = 1
def key = "key:${id}"		// this is a GString
map[key] = "Groovy"			// automatic conversion from GString to String happens here. The value is stored with a String key
assert map.containsKey(key) // THIS WILL FAIL because the containsKey method accepts Object, therefore no conversion to String happens. The key has different hashCode.

To get around this, the safest way according to the Groovy documentation is to avoid using GString as keys in hash maps at all. If you still want to use it, the following approach will work:

String key = "key:${id}" // explicitly setting the data type to String will work
map.containsKey(key.toString()) // explicitly converting the key to String will work as well

Found an issue in documentation? Write to us.