Lazy field initialization with lambdas
Asked Answered
C

15

58

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.

Condescend answered 18/3, 2015 at 21:18 Comment(6)
Just do like this post https://mcmap.net/q/86663/-when-should-i-use-lazy-lt-t-gtCarib
That's for .Net. But is there any Lazy equivalent in Java?Condescend
@Condescend I think some of the confusion is that there are both C# and Java-8 tags on your question. Perhaps you could edit the question to make it more clear you want a Java-8 solution that mimics C# behavior.Pothole
See Guava's Suppliers.memoizeJutta
Related: #8298205Admittedly
You could also check out vavr solution.Mathura
L
41

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.

Literary answered 18/3, 2015 at 21:41 Comment(0)
K
30

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.

Kiyokokiyoshi answered 19/3, 2015 at 5:57 Comment(8)
What would be the disadvantages of implementing lazily with a captured AtomicReference<Supplier<Z>>?Newsman
Example implementation: static <Z> Supplier<Z> lazily(Supplier<Z> supplier) { AtomicReference<Supplier<Z>> value = new AtomicReference<>(); return () -> value.updateAndGet(v -> v -= null ? supplier.get() : v); }Newsman
@Newsman Did you mean AtomicReference<Z>?Kiyokokiyoshi
@Newsman It'll work, but unfortunately updateAndGet() doesn't really have the transactional semantics we want. It can be called multiple times and so the doc warns against side effects. That won't occur in the OP's case, but still. Also, an unconditional updateAndGet() incurs a volatile read and write every time. Maybe not a big deal, but strictly not necessary.Kiyokokiyoshi
@Newsman You could also use AtomicReference<Supplier<Z>>, initialize it with the heavyweight initializer, which sets it to a supplier that returns the cache the next time. At this point the AtomicRef is just a holder for a reference; might as well just write a class and use a field.Kiyokokiyoshi
@StuartMarks, nice application of my approach. I appreciated the idea of the lazily utility functionLiterary
@MiguelGamboa Looks like we're all building on each others' ideas!Kiyokokiyoshi
@MiguelGamboa and Stuart - FWIW I added this and many of the other methods here to this benchmark. The JIT does a good job with all of them and the cost is pretty much negligible compared to a non-lazy approach, so I wouldn't worry about performance and just pick whatever is cleanest on a per-field basis and most functional.Closer
S
23

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.

Sweatbox answered 19/3, 2015 at 10:14 Comment(6)
Your lazily function is awesome. I had to take I while to process it!Literary
One downside of this approach is the fieldBaz changes implementations before/after the first init. Since hotspot profiles call sites to see how many different implementations are at a call site, I think this results in slightly less optimistic code at the call site. In essence, the cost for getting the nice unconditional Supplier is likely an slightly more complex code at the call site (although it may end up having exactly 1 hidden branch which is probably the same as Stuart's solution).Closer
@BeeOnRope: I doubt that the first invocation’s behavior has any significance, especially in the current JVM using tiered compilation. Having “almost monomorphic” call sites that change only rarely, is very common and has to be considered by a reasonable optimizer. When the change only happens at the first invocation, there even won’t be anything that has to be de-optimized (unless expensiveInit…() turns out to be actually a trivial method).Sweatbox
@Holger: indeed, compilers are good at compiling sites with varying degrees of polymorphism, but it still produces different code if only a single class has ever been "seen" at a call site, versus 2, versus 3 or more, etc (and it depends on the frequencies). You are possibly right though that since the "other" type is only on the first invocation, it's possible that JIT won't even know that one time other was used because statistics weren't being kept at that point. Also, it could be that the bimorphic code is just as fast as the conservative monomorphic code anyway (but a bit larger).Closer
FWIW, I benchmarked pretty much all the methods here with JMH. They are all very close, mostly about 1 cycle (~0.3 ns) slower than a "default" non-lazy method of returning a static final Object. About half of the cost is related to generics and erasure it seems - T is erased to Object which needs to be casted back to Integer when the benchmark methods returns (casting is also needed in the real world). If you declare a type-specific Lazy class you cut this cost out. Overall though I would just do whatever is simplest, probably along the lines of Stuart's suggestion.Closer
Here's the benchmark in case anyone else wants to play with it.Closer
R
19

Project Lombok provides a @Getter(lazy = true) annotation which does exactly what you need.

Regalado answered 3/2, 2016 at 8:44 Comment(0)
G
6

How about this? then you can do something like this by using LazyInitializer from Apache Commons: https://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/concurrent/LazyInitializer.html

private static Lazy<Double> _lazyDouble = new Lazy<>(()->1.0);

class Lazy<T> extends LazyInitializer<T> {
    private Supplier<T> builder;

    public Lazy(Supplier<T> builder) {
        if (builder == null) throw new IllegalArgumentException();
        this.builder = builder;
    }
    @Override
    protected T initialize() throws ConcurrentException {
        return builder.get();
    }
}
German answered 25/5, 2016 at 16:57 Comment(5)
That's not Lazy. That will be always invoking the inner builder.Condescend
I've tested and it works. Note it inherits from LazyInitializer class.German
Is that c# or Java? I think LazyInitializer is part of .Net standard libraries, but here you provide a Java example, since you are using an Override annotation.Condescend
@Condescend I just switched to Java from .Net, but this one is from Java Apache library: commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/…German
@HiddenDragon You should probably mention about apache commons in the answer.Meshwork
E
3

It's supported,

By creating a small interface and combining 2 new features introduced in java 8:

  • @FunctionalInterface annotation (allows assigning a lambda on declaration)
  • default keyword (define an implementation, just like abstract class - but in an interface)

It is possible to get the same Lazy<T> behavior as you seen in C#.


Usage

Lazy<String> name = () -> "Java 8";
System.out.println(name.get());

Lazy.java (copy and paste this interface in somewhere accessible)

import java.util.function.Supplier;

@FunctionalInterface
public interface Lazy<T> extends Supplier<T> {
    abstract class Cache {
        private volatile static Map<Integer, Object> instances = new HashMap<>();

        private static synchronized Object getInstance(int instanceId, Supplier<Object> create) {

            Object instance = instances.get(instanceId);
            if (instance == null) {
                synchronized (Cache.class) {
                    instance = instances.get(instanceId);
                    if (instance == null) {
                        instance = create.get();
                        instances.put(instanceId, instance);
                    }
                }
            }
            return instance;
        }
    }

    @Override
    default T get() {
        return (T) Cache.getInstance(this.hashCode(), () -> init());
    }

    T init();
}

Online Example - https://ideone.com/3b9alx

The following snippet demonstrates the lifecycle of this helper class

static Lazy<String> name1 = () -> { 
    System.out.println("lazy init 1"); 
    return "name 1";
};
    
static Lazy<String> name2 = () -> { 
    System.out.println("lazy init 2"); 
    return "name 2";
};

public static void main (String[] args) throws java.lang.Exception
{
    System.out.println("start"); 
    System.out.println(name1.get());
    System.out.println(name1.get());
    System.out.println(name2.get());
    System.out.println(name2.get());
    System.out.println("end"); 
}

will output

start
lazy init 1
name 1
name 1
lazy init 2
name 2
name 2
end

See the online demo - https://ideone.com/3b9alx

Enjoin answered 29/3, 2016 at 9:29 Comment(5)
It's not safe to use hashCode() as a Map key in this manner. Two objects may get the same hashCode.Stephan
@ChristofferHammarström you are correct, thanks for the comment. would java.lang.System.identityHashCode(obj); do the trick?Enjoin
Just use the object itself as the key in an IdentityHashMap.Stephan
There is another concern though. Cache invalidation. How is anything ever removed from the map? Looks like a major memory leak.Stephan
@ChristofferHammarström Thanks! I'll switch to the object reference itself. regarding cache: intentionally keeps stored result references until you shutdown your process. I agree, however this is something to consider per use caseEnjoin
R
1

You could do something along these lines :

   private Supplier heavy = () -> createAndCacheHeavy();

   public Heavy getHeavy()
   {
      return heavy.get();
   }

   private synchronized Heavy createAndCacheHeavy()
   {
      class HeavyFactory implements Supplier
      {
         private final Heavy heavyInstance = new Heavy();

         public Heavy get()
         {
            return heavyInstance;
         }
      }

      if(!HeavyFactory.class.isInstance(heavy))
      {
         heavy = new HeavyFactory();
      }

      return heavy.get();
   }

I recently saw this as an idea by Venkat Subramaniam. I copied the code from this page.

The basic idea is that the Supplier once called, replaces itself with a simpler factory implementation that returns the initialized instance.

This was in the context of thread safe lazy initialization of a singleton, but you could also apply it to a normal field, obviously.

Ruder answered 18/3, 2015 at 21:39 Comment(0)
D
1

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);
Debbiedebbra answered 19/3, 2015 at 7:17 Comment(0)
H
1

If you need something that approximates the behaviour of Lazy in C#, which gives you thread safety and a guarantee that you always get the same value, there is no straightforward way to avoid if.

You will need to use a volatile field and double checked locking. Here is the lowest memory footprint version of a class that gives you the C# behaviour:

public abstract class Lazy<T> implements Supplier<T> {
    private enum Empty {Uninitialized}

    private volatile Object value = Empty.Uninitialized;

    protected abstract T init();

    @Override
    public T get() {
        if (value == Empty.Uninitialized) {
            synchronized (this) {
                if (value == Empty.Uninitialized) {
                    value = init();
                }
            }
        }
        return (T) value;
    }

}

It's not that elegant to use. You would have to create lazy values like this:

final Supplier<Baz> someBaz = new Lazy<Baz>() {
    protected Baz init(){
        return expensiveInit();
    }
}

You can gain some elegance at the cost of additional memory footprint, by adding a factory method like this:

    public static <V> Lazy<V> lazy(Supplier<V> supplier) {
        return new Lazy<V>() {
            @Override
            protected V init() {
                return supplier.get();
            }
        };
    }

Now you can create thread safe lazy values simply like this:

final Supplier<Foo> lazyFoo = lazy(() -> fooInit());
final Supplier<Bar> lazyBar = lazy(() -> barInit());
final Supplier<Baz> lazyBaz = lazy(() -> bazInit());
Hydroxyl answered 20/2, 2018 at 22:2 Comment(0)
I
1

Well, I don't really suggest having no "if", but here's my take on the matter:

One simple method is to use an AtomicReference (the ternary operator is still like an "if"):

private final AtomicReference<Something> lazyVal = new AtomicReference<>();

void foo(){
    final Something value = lazyVal.updateAndGet(x -> x != null ? x : expensiveCreate());
    //...
}

But then there is the whole thread safety magic that one might not need. So I'd do it like Miguel with a little twist:

Since I like simple one-liners, I simply use a ternary operator (again, reads like an "if") but I'd let Java's evaluation order do its magic to set the field:

public static <T> Supplier<T> lazily(final Supplier<T> supplier) {
    return new Supplier<T>() {
        private T value;

        @Override
        public T get() {
            return value != null ? value : (value = supplier.get());
        }
    };
}

gerardw's field-modification example above, that works without an "if", can be further simplified too. We don't need the interface. We just need to exploit above "trick" again: An assignment operator's result is the assigned value, we can use brackets to force evaluation order. So with the method above it's just:

static <T> Supplier<T> value(final T value) {
   return () -> value;
}


Supplier<Point> p2 = () -> (p2 = value(new Point())).get();

Note that you cannot inline the "value(...)" method without losing the laziness.

Idioblast answered 20/5, 2018 at 13:53 Comment(0)
A
0

How about this. Some J8 functional switcheroos to avoid ifs on each access. Warning: not thread aware.

import java.util.function.Supplier;

public class Lazy<T> {
    private T obj;
    private Supplier<T> creator;
    private Supplier<T> fieldAccessor = () -> obj;
    private Supplier<T> initialGetter = () -> {
        obj = creator.get();
        creator = null;
        initialGetter = null;
        getter = fieldAccessor;
        return obj;
    };
    private Supplier<T> getter = initialGetter;

    public Lazy(Supplier<T> creator) {
        this.creator = creator;
    }

    public T get() {
        return getter.get();
    }

}
Arriola answered 21/12, 2016 at 6:58 Comment(0)
M
0

Stuart Mark's solution, with an explicit class. (Whether this is "better" is a personal preference thing, I think.)

public class ScriptTrial {

static class LazyGet<T>  implements Supplier<T> {
    private T value;
    private Supplier<T> supplier;
    public LazyGet(Supplier<T> supplier) {
        value = null;
        this.supplier = supplier;
    }

    @Override
    public T get() {
        if (value == null)
            value = supplier.get();
        return value;
    }

}

Supplier<Integer> lucky = new LazyGet<>(()->seven());

int seven( ) {
    return 7;
}

@Test
public void printSeven( ) {
    System.out.println(lucky.get());
    System.out.println(lucky.get());
}

}

Mascle answered 31/3, 2018 at 19:57 Comment(0)
K
0

2 solutions, one functional then and one object (it's same code), thread safe, without "if", and taking care of Exception handling with proper type propagation (no solution here take care about that).

It is quite short. Better lazy fields support, handled by the runtime, will eventually make this code obsolete...

usage :

// object version : 2 instances (object and lambda)
final Lazy<Integer, RuntimeException> lazyObject = new LazyField<>(() -> 1);

// functional version : more efficient than object, 1 instance
// usage : wrap computed value using eval(arg), and set the lazy field with result
Lazy<Service, IOException> lazyFunc = lazyField(() -> this.lazyFunc = eval(new Service()));

// functional final version, as field is final this is less efficient than object :
// 2 instances one "if" and one sync (that could still be avoided...)
final Lazy<Integer, RuntimeException> finalFunc = lazyField(() -> eval(1));

// Here the checked exception type thrown in lambda can only be ServiceException
static Lazy<Integer, ServiceException> lazyTest = lazyField(() -> {throw new ServiceException();});

First I define a lambda with exception :

@FunctionalInterface
interface SupplierWithException<T, E extends Exception> {
    T get() throws E;
}

Then a Lazy type :

interface Lazy<T, E extends Exception> extends SupplierWithException<T, E> {}

Functional version :

It directly returns a lambda that eventually get the less memory footprint, if not used on a final field like in sample above.

static <T, E extends Exception> Lazy<T, E> lazyField(Lazy<Lazy<T, E>, E> value) {
    Objects.requireNonNull(value);
    Lazy<T, E>[] field = new Lazy[1];
    return () -> {
        synchronized(field) {
            if(field[0] == null)
                field[0] = value.get();
            return field[0].get();
        }
    };
}

static <T, E extends Exception> Lazy<T, E> eval(T value) {
    return () -> value;
}

One can not enforce to give a correct value callback, at least it always returns the same result but may not avoid the "if" (as in final field case).

Object version :

Is fully safe from the outside.

public final class LazyField<T, E extends Exception> implements Lazy<T, E> {

    private Lazy<T, E> value;

    public LazyField(SupplierWithException<T, E> supplier) {
        value = lazyField(() -> new Lazy<T, E>() {
            volatile Lazy<T, E> memBarrier;
            @Override
            public T get() throws E {
               value = memBarrier = eval(supplier.get());
            }
        });
    }

    @Override
    public T get() throws E {
        return value.get();
    }
}

the read of field value is unordered, but use of volatile memBarrier field ensure ordering of value written in this field. The initial lambda set in this field will also returns initialized lazy value if called after the lazy value was effectively set.

enjoy

Kaolack answered 10/7, 2019 at 18:14 Comment(0)
W
0

Similar to Miguel Gamboa's answer, but using an Optional instead of a Supplier.

class A<T> {
    // start empty, first access will set real value
    private Optional<T> fooField = Optional.empty();

    public T getFoo() {
        return fooField.orElseGet(() -> {
            T foo = expensiveInit();
            this.fooField = Optional.ofNullable(foo);
            return foo;
        });
    }
}
Waite answered 26/10, 2023 at 16:41 Comment(0)
A
-2

Here's a solution using Java's Proxy (reflection) and Java 8 Supplier.

* Because of the Proxy usage, the initiated object must implement the passed interface.

* The difference from other solutions is the encapsulation of the initiation from the usage. You start working directly with DataSource as if it was initialized. It will be initialized on the first method's invocation.

Usage:

DataSource ds = LazyLoadDecorator.create(() -> initSomeDS(), DataSource.class)

Behind the scenes:

public class LazyLoadDecorator<T> implements InvocationHandler {

    private final Object syncLock = new Object();
    protected volatile T inner;
    private Supplier<T> supplier;

    private LazyLoadDecorator(Supplier<T> supplier) {
        this.supplier = supplier;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (inner == null) {
            synchronized (syncLock) {
                if (inner == null) {
                    inner = load();
                }
            }
        }
        return method.invoke(inner, args);
    }

    protected T load() {
        return supplier.get();
    }

    @SuppressWarnings("unchecked")
    public static <T> T create(Supplier<T> supplier, Class<T> clazz) {
        return (T) Proxy.newProxyInstance(LazyLoadDecorator.class.getClassLoader(),
                new Class[] {clazz},
                new LazyLoadDecorator<>(supplier));
    }
}
Admittedly answered 11/1, 2017 at 17:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.