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 b
Here's a way that also works if you want to pass arguments (which you dont have when initializing the functional interface) to your expensiveInit
method.
public final class Cache<T> {
private Function<Supplier<? extends T>, T> supplier;
private Cache(){
supplier = s -> {
T value = s.get();
supplier = n -> value;
return value;
};
}
public static <T> Supplier<T> of(Supplier<? extends T> creater){
Cache<T> c = new Cache<>();
return () -> c.supplier.apply(creater);
}
public static <T, U> Function<U, T> of(Function<? super U, ? extends T> creater){
Cache<T> c = new Cache<>();
return u -> c.supplier.apply(() -> creater.apply(u));
}
public static <T, U, V> BiFunction<U, V, T> of(BiFunction<? super U, ? super V, ? extends T> creater){
Cache<T> c = new Cache<>();
return (u, v) -> c.supplier.apply(() -> creater.apply(u, v));
}
}
Usage is the same as Stuart Marks' answer:
private final Function<Foo, Bar> lazyBar = Cache.of(this::expensiveBarForFoo);
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.