Loading...

May 2, 2011

Groovy Goodness: Cache Closure Results with Memoization

Closures are very powerful in Groovy. Groovy 1.8 introduces closure memoization. This means we can cache the result of a closure, so the next time we invoke the closure the result is returned immediately. This is very useful for time consuming computations in a closure.

To use this feature we invoke the memoize() method on a closure. Now the results from calls to the closure are cached. We can use three other methods to define for example the maximum number of calls to cache, or the least number of calls with memoizeAtMost(), memoizeAtLeast() and memoizeBetween().

// Closure simple increments parameter.
// Also script variable incrementChange is 
// changed so we can check if the result is
// from a cached call or not.
def incrementChange = false
def increment = { 
    incrementChange = true
    it + 1 
}
// Just invoke the closure 5 times with different parameters.
(0..5).each {
    incrementChange  = false
    assert increment(it) == it + 1
    assert incrementChange
}
incrementChange = false
assert increment(1) == 2  // Call is not cached.
assert incrementChange  

// Use memoize() so all calls are cached.
incrementChange = false
def incrementMemoize = increment.memoize()
// Just invoke the closure 5 times with different parameters.
(0..5).each {
    incrementChange = false
    assert incrementMemoize(it) == it + 1
    assert incrementChange
}
incrementChange = false
assert incrementMemoize(2) == 3  // Cached call.
assert !incrementChange  

// Use memoizeAtMost().
incrementChange = false
def memoizeAtMostOnce = increment.memoizeAtMost(1)
// Just invoke the closure 5 times with different parameters.
(0..5).each {
    incrementChange = false
    assert memoizeAtMostOnce(it) == it + 1
    assert incrementChange
}
incrementChange = false
assert memoizeAtMostOnce(1) == 2  // 2nd call is not cached.
assert incrementChange