Lazy field initialization with lambdas

rodolfino picture rodolfino · Mar 18, 2015 · Viewed 33.4k times · Source

I would like to implement lazy field initialization (or deferred initialization) without an if statement and taking advantage of lambdas. So, I would like to have the same behavior of the following Foo property but without the if:

class A<T>{
    private T fooField;

    public T getFoo(){
        if( fooField == null ) fooField = expensiveInit();
        return fooField;
    }
}

Ignore the fact that this solution is not guaranteeing safe use for: 1) multi-threading; 2) null as a valid value of T.

So, to express the intention that the initialization of the fooField is deferred until its first use I would like to declare the fooField of the type Supplier<T> such as:

class A<T>{
   private Supplier<T> fooField = () -> expensiveInit();

   public T getFoo(){
      return fooField.get();
   }
}

and then in the getFoo property I would just return fooField.get(). But now I want that next invocations to getFoo property avoid the expensiveInit() and just return the previous T instance.

How can I achieve that without using an if?

Despite naming conventions and replacing the ->by =>, then this example could be also considered in C#. However, NET Framework version 4 already provides a Lazy<T> with the desired semantics.

Answer

Miguel Gamboa picture Miguel Gamboa · Mar 18, 2015

Within your actual lambda, you can simply update the fooField with a new lambda, such as:

class A<T>{
    private Supplier<T> fooField = () -> {
       T val = expensiveInit();
       fooField = () -> val;
       return val;
    };

    public T getFoo(){
       return fooField.get();
    }
}

Again this solution is not thread-safe as is the .Net Lazy<T>, and does not ensure that concurrent calls to the getFoo property return the same result.