I wrote the following code to simulate Lazy<T> in Java:
import java.util.function.Supplier;
public class Main {
    @FunctionalInterface
    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; }
    private static Lazy<Thing> thing = lazily(()->thing=value(new Thing()));
    public static void main(String[] args) {
        System.out.println("One");
        Thing t = thing.get();
        System.out.println("Three");
    }
    static class Thing{ Thing(){System.out.println("Two");}}
}
but I get the following warning:
"value
(T)in Main cannot be applied to (com.company.Main.Thing) reason: no instance(s) of type variable(s) T exist so thatSupplier<T>conforms toLazy<Thing>"
could you please help me find out what the problem is? thanks in advance!
Lazy is a subclass of Supplier and you are trying to cast it otherways.
Changing
private static Lazy<Thing> thing = lazily(() -> thing = value(new Thing()));
to
private static Supplier<Thing> thing = lazily(() -> thing = value(new Thing()));
should work.
value() returns a Supplier, while thing field has type Lazy<Thing>. You cannot assign a Supplier to a Lazy (with whatever parametrization) because not all Supplier instances are Lazy instances.
Further, lazily() return value (which is a Supplier) is tried to be assigned to the thing, and this is not gonna work for the same reason.
We can change lazily type to Lazy and remove that inline thing= assignment (which is inside thing initializer expression) to make it compile:
static <U> Lazy<U> lazily(Lazy<U> lazy) { return lazy; }
static <T> Supplier<T> value(T value) { return ()->value; }
private static Lazy<Thing> thing = lazily(()->value(new Thing()));
But I'm not sure whether this is what you wanted to get.
If you just wanted a lazy behaviour, Supplier itself is already capable of acting lazy as get() is only executed when requested to and not when a Supplier is created.
If you want a caching logic (only compute once, and only compute it needed), you could use something like this:
public class CachingSupplier<T> implements Supplier<T> {
    private final Supplier<T> supplier;
    private T cachedValue;
    private boolean computed = false;
    public CachingSupplier(Supplier<T> supplier) {
        this.supplier = supplier;
    }
    public T get() {
        if (!computed) {
            cachedValue = supplier.get();
            computed = true;
        }
        return cachedValue;
    }
}
If you want to guarantee that supplier.get() gets called at maximum once, you could apply some synchronization:
    if (!computed) {
        synchronized (this) {
            if (!computed) {
                cachedValue = supplier.get();
                computed = true;
            }
        }
    }
    return cachedValue;
Here, a double-checked locking is used.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With