Simulate Lazy in Java8

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:

"the value (T) in the main cannot be applied to ( com.company.Main.Thing ) Reason: there is no instance (s) of type (s) of type T, so Supplier<T> matches Lazy<Thing> "

Could you help me find out what the problem is? thanks in advance!

+5
source share
2 answers

Lazy is a subclass of Supplier , and you are trying to use it differently.

The change

 private static Lazy<Thing> thing = lazily(() -> thing = value(new Thing())); 

to

 private static Supplier<Thing> thing = lazily(() -> thing = value(new Thing())); 

must work.

+4
source

value() returns a Supplier , and the thing field is of type Lazy<Thing> . You cannot assign Supplier a Lazy (with any parameterization), because not all Supplier instances are Lazy instances.

In addition, lazily() returns the Supplier value) for the thing , and this will not work for the same reason.

We can change the lazily type to Lazy and remove the inline thing= assignment (which is inside the thing expression) to compile it:

 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 that this is what you wanted to get.

If you just wanted lazy behavior, the Supplier itself is already lazy, because get() is executed only on request, and not when creating the Supplier .

If you need caching logic (only calculate once and only need to calculate it), you can 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() will be called at most once, you can apply some synchronization:

  if (!computed) { synchronized (this) { if (!computed) { cachedValue = supplier.get(); computed = true; } } } return cachedValue; 

A double-checked lock is used here.

+1
source

Source: https://habr.com/ru/post/1272819/


All Articles