24

I know of this one http://onjava.com/pub/a/onjava/2003/08/20/memoization.html but is there anything else?

2
  • 1
    This example does memoization on all methods of an object via a proxy. But typical memoization is one function at the time. That proxy technique would be annoying when you dont want to memoize all the methods of an object. Commented Sep 2, 2010 at 5:45
  • After lots of looking, I finally just originated my own: gist.github.com/chaotic3quilibrium/… Commented Nov 22, 2023 at 0:09

3 Answers 3

23

To memoize functions without parameters, use Guava's Suppliers.memoize(Supplier). For functions with parameters, use CacheBuilder.build(CacheLoader) with parameter value objects as keys.

Sign up to request clarification or add additional context in comments.

2 Comments

17

Yes. Use caches from Guava.

Example:

import java.math.BigInteger;

import com.google.common.base.Preconditions;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

public class Fibonacci {
    private static final LoadingCache<Integer, BigInteger> CACHE
            = CacheBuilder.newBuilder().build(CacheLoader.from(Fibonacci::fib));

    public static BigInteger fib(int n) {
        Preconditions.checkArgument(n >= 0);
        switch (n) {
        case 0:
            return BigInteger.ZERO;
        case 1:
            return BigInteger.ONE;
        default:
            return CACHE.getUnchecked(n - 1).add(CACHE.getUnchecked(n - 2));
        }
    }
}

2 Comments

MapMaker is now deprecated in favour of CacheBuilder: code.google.com/p/guava-libraries/wiki/MapMakerMigration
@dzieciou I've finally updated the code to something that works with the latest Guava (18.0 at current time of writing). And this time, it's tested!
15

Memoization is also easy with plain simple typesafe Java.

You can do it from scratch with the following reusable classes.

I use these as caches whose lifespan are the request on a webapp.

Of course use the Guava MapMaker if you need an eviction strategy or more features like synchronization.

If you need to memoize a method with many parameters, just put the parameters in a list with both techniques, and pass that list as the single parameter.

abstract public class Memoize0<V> {
    //the memory
    private V value;
    public V get() {
        if (value == null) {
            value = calc();
        }
        return value;
    }
    /**
     * will implement the calculation that 
     * is to be remembered thanks to this class
     */
    public abstract V calc();
}

abstract public class Memoize1<P, V> {
    //The memory, it maps one calculation parameter to one calculation result
    private Map<P, V> values = new HashMap<P, V>();

    public V get(P p) {
        if (!values.containsKey(p)) {
            values.put(p, calc(p));
        }
        return values.get(p);
    }

    /**
     * Will implement the calculations that are
     * to be remembered thanks to this class
     * (one calculation per distinct parameter)
     */
    public abstract V calc(P p);
 }

And this is used like this

    Memoize0<String> configProvider = new Memoize0<String>() {
        @Override
        public String calc() {
            return fetchConfigFromVerySlowDatabase();
        }
    };
    final String config = configProvider.get();

    Memoize1<Long, String> usernameProvider = new Memoize1<Long, String>() {
        @Override
        public String calc(Long id) {
            return fetchUsernameFromVerySlowDatabase(id);
        }
    };
    final String username = usernameProvider.get(123L);

6 Comments

Guava is not approved yet for our environment, financial software...
Guava is not approved for our environment yet. Banking software... But this will do. I will limit the size of the map however to avoid memory leaks. I dont care about evictions since this will be conserved only during the invocation of one method.
I like the way highly tested code is not approved, but something pasted on SO is :)
Be cautious using the Memoize0 example since it's not thread-safe. Multiples threads may call the calc() method numerous time in a race-condition. The Guava is implementation is thread-safe, lock-free on get() once initialized because it uses double-check locking : github.com/google/guava/blob/master/guava/src/com/google/common/…
It looks like MapMaker doesn't exist (anymore). Try CacheBuilder instead.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.