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