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