Lazy field initialization with lambdas

后端 未结 14 2268
日久生厌
日久生厌 2020-11-29 23:39

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

相关标签:
14条回答
  • 2020-11-30 00:24

    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);
    
    0 讨论(0)
  • 2020-11-30 00:30

    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.

    0 讨论(0)
提交回复
热议问题