Groovy Method References

I was listening to a podcast recently about Eclipse tooling for Java 8 and heard them talking about method references, and one of my co-workers mentioned it as a feature in Groovy. I recently ran across a problem which seemed particular well suited for this feature.

I had a list with different implementations of the Field class which each had a form of a get... method. For instance the ExternalDecimalAsInt has a getInt method, while the StringField has getString. method.  Both methods parse a byte stream and return the data. Since I'm writing Groovy, I don't care about the data type, I just wanted a simple way to invoke the get... method, regardless of the class type.

So I created a method reference in my object, and using a switch statement load the method reference according to the type of object that I'm dealing with.

class MyObject {
  def MethodClosure read //probably would omit the data type normally
} 

private void generateReader(MyObject myObject, Field field) {
  switch (field) {
    case StringField:
      myObject.read = field.&getString
      break
    case IntAccessor:
      myObject.read = field.&getInt
      break
    case BigDecimalAccessor:
      myObject.read = field.&getBigDecimal
      break
    case LongAccessor:
      myObject.read = field.&getLong
      break
    case BigIntegerAccessor:
      myObject.read = field.&getBigInteger
      break
  }
}

//invokes getString, getInt, etc... depending on the object type
def value = myObject.read(bytes) 



Of course, you can always do the same thing with closures, but there's a little less syntax with the method references, and it looks cooler. Once I can use Java 8, I hear that method references are also more efficient than lamba expressions, the equivalent to Groovy closures.

case StringField:
  myObject.read = { field.getString() }

Groovy LazyMap - Caching Map

I was working on a Groovy class recently which involved putting a series of closures into a map to do some processing when invoked, but I realized that I didn't really want to run the closures each time they were accessed, once they ran the first time, I would prefer that the data was cached. So the code would look something like this.

Map myProcesses = [coolId : { retriever.somehow() }]
myProcesses.coolId() // <-- the first time this invokes a method call
myProcesses.coolId() // <-- should return value stored from the last call

The use of the closures worked nicely, I just had to figure out how to handle caching. At first I looked into the memoize method on my closures, but there seemed to be some disconnect between how I was trying to use them and what Groovy wanted. When I used coolId() it complained that the method doCall was not available. So, I'm not exactly sure what was happening there.

Map myProcesses = [coolId : { retriever.somehow() }.memoize()]

Then I realized I should be able to do something simpler anyway. Really I wanted a LazyMap, I 
didn't need caching on each individual closure. I had used the LazyMap class provided in the apache commons library to do the following.

return org.apache.commons.collections4.Map.LazyMap.lazyMap(
  new HashMap<String, MyObject>(),
  new org.apache.commons.collections4.Transformer<String, MyObject>() {
    @Override
    public MyObject transform(String input) {
      return retriever.goGetIt(input);
    }
  });

I also remembered coming across some LazyMap references in Groovy, so I did some looking, but the only class I found was in the groovy.json.internal package. Probably not a class I should be using. Was it possible that Groovy didn't have an implementation of a LazyMap? That seemed unlikely to me, almost everything in the commons libraries seem to be built into Groovy. So I started looking at the Groovy docs and ran across the withDefault method that Groovy added to Maps. I realized that an empty map whose default method would invoke my closures and store the results was exactly what I wanted.

Map myInnerProcesses = [coolId : { retriever.somehow() }]
Map myProcesses = [:].withDefault { myInnerProcesses[it] }
myProcesses.coolId() // <-- the first time this invokes a method call
myProcesses.coolId() // <-- should return value stored from the last call

So, by using withDefault I was able to add caching in a single line of code.