Lazy field initialization with lambdas

Taking Miguel Gamboa’s solution and trying to minimize the per-field code without sacrificing its elegance, I came to the following solution:

interface Lazy<T> extends Supplier<T> {
    Supplier<T> init();
    public default T get() { return init().get(); }
}
static <U> Supplier<U> lazily(Lazy<U> lazy) { return lazy; }
static <T> Supplier<T> value(T value) { return ()->value; }

Supplier<Baz> fieldBaz = lazily(() -> fieldBaz=value(expensiveInitBaz()));
Supplier<Goo> fieldGoo = lazily(() -> fieldGoo=value(expensiveInitGoo()));
Supplier<Eep> fieldEep = lazily(() -> fieldEep=value(expensiveInitEep()));

The per-field code only slightly bigger than in Stuart Marks’s solution but it retains the nice property of the original solution that after the first query, there will be only a lightweight Supplier which unconditionally returns the already computed value.


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.


The approach taken by Miguel Gamboa's answer is a fine one:

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

It works well for one-off lazy fields. However, if more than one field needs to be initialized this way, the boilerplate would have to be copied and modified. Another field would have to be initialized like this:

private Supplier<T> barField = () -> {
   T val = expensiveInitBar();          // << changed
   barField = () -> val;                // << changed
   return val;
};

If you can stand one extra method call per access after the initialization, I'd do it as follows. First, I'd write a higher-order function that returns an instance of Supplier that contains the cached value:

static <Z> Supplier<Z> lazily(Supplier<Z> supplier) {
    return new Supplier<Z>() {
        Z value; // = null
        @Override public Z get() {
            if (value == null)
                value = supplier.get();
            return value;
        }
    };
}

An anonymous class is called for here because it has mutable state, which is the cached of the initialized value.

Then, it becomes quite easy to create many lazily initialized fields:

Supplier<Baz> fieldBaz = lazily(() -> expensiveInitBaz());
Supplier<Goo> fieldGoo = lazily(() -> expensiveInitGoo());
Supplier<Eep> fieldEep = lazily(() -> expensiveInitEep());

Note: I see in the question that it stipulates "without using an if". It wasn't clear to me whether the concern here is over avoiding the runtime expensive of an if-conditional (really, it's pretty cheap) or whether it's more about avoiding having to repeat the if-conditional in every getter. I assumed it was the latter, and my proposal addresses that concern. If you're concerned about runtime overhead of an if-conditional, then you should also take the overhead of invoking a lambda expression into account.