code: public Closure<V> memoizeAtMost(final int maxCacheSize) {
          if (maxCacheSize < 0) throw new IllegalArgumentException("A non-negative number is required as the maxCacheSize parameter for memoizeAtMost.");
  
          return Memoize.buildMemoizeFunction(new LRUCache(maxCacheSize), this);
      }
docs: Creates a caching variant of the closure with upper limit on the cache size.
  Whenever the closure is called, the mapping between the parameters and the return value is preserved in cache
  making subsequent calls with the same arguments fast.
  This variant will keep all values until the upper size limit is reached. Then the values in the cache start rotating
  using the LRU (Last Recently Used) strategy.
  The returned function can be safely used concurrently from multiple threads, however, the implementation
  values high average-scenario performance and so concurrent calls on the memoized function with identical argument values
  may not necessarily be able to benefit from each other's cached return value. With this having been mentioned,
  the performance trade-off still makes concurrent use of memoized functions safe and highly recommended.
  
  The cache gets garbage-collected together with the memoized closure.
  
  @param maxCacheSize The maximum size the cache can grow to
  @return A new function forwarding to the original one while caching the results