Search code examples
javareferencelazy-loadingguava

Lazy loading reference implementation


Being impressed by Guava's computing map feature, I'm searching for a sort of "computing reference" - a lazy loading reference implementation that parallel's Guava's ease of use, by which I mean it handles all locking, loading, and exception handling under the hood, only exposing a get() method.

After a brief search turned up nothing, I quickly rolled my own as a proof of concept:

public abstract class ComputingRef<T> implements Callable<T> {

   private volatile T referent = null;
   private Lock lock = new ReentrantLock();

   public T get() {
      T temp = referent;
      if (temp == null) {
         lock.lock();
         try {
            temp = referent;
            if (temp == null) {
               try {
                  referent = temp = call();
               }
               catch (Exception e) {
                  if (e instanceof RuntimeException) {
                     throw (RuntimeException)e;
                  }
                  else {
                     throw new RuntimeException(e);
                  }
               }
            }
         }
         finally {
            lock.unlock();
         }
      }
      return temp;
   }
}

This ComputingRef could be anonymously extended to implement call(), which functions as the factory method:

ComputingRef<MyObject> lazySingletonRef = new ComputingRef<MyObject>() {
   @Override
   public MyObject call() {
      //fetch MyObject from database and return
   }
};

I'm not satisfied that this implementation is optimal, but it demonstrates what I'm after.

I later found this example from the T2 Framework, which appears to be more complex.

Now my questions are:

  • How can my above code be improved?
  • How does it compare to the T2 example, and what advantages are offered by that example's greater complexity?
  • Are there other implementations of a lazy loading reference that I've missed in my search?

EDIT: Updated my implementation to use a local variable as suggested by @irreputable's answer - please upvote it if you find the above example useful.


Solution

  • See Suppliers.memoize(Supplier) to lazily initialize a value.