2017-10-23 8 views
5

Ich schrieb den folgenden Code Lazy<T> in Java zu simulieren:simulieren Faul in Java8

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");}} 
} 

aber ich erhalte die folgende Warnung:

„Wert (T) in Main kann nicht auf (com.company.Main.Thing) angewendet werden, Grund: keine Instanz (en) vom Typ Variable (n) T vorhanden ist, so dass Supplier<T> zu Lazy<Thing> "

entspricht

Könnten Sie mir bitte helfen herauszufinden, was das Problem ist? danke im voraus!

+1

Folgen Sie [der Vorlage] (https://Stackoverflow.com/a/29141814/2711488) * streng * ... – Holger

Antwort

1

value() gibt ein Supplier, während thing Feld eingeben Lazy<Thing> hat. Sie können Supplier keinem Lazy (mit welcher Parametrierung) zuweisen, da nicht alle Supplier Instanzen Lazy Instanzen sind.

Ferner lazily() Rückgabewert (der ein Supplier ist) wird versucht, die thing zugeordnet werden, und das ist ja gar nicht aus dem gleichen Grund.

Wir lazily Typen Lazy ändern und entfernen Sie die Inline-thing= Zuordnung (die thing initializer Ausdruck innen) kompilieren zu machen:

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())); 

Aber ich bin nicht sicher, ob dies ist, was Sie wollten bekommen.

Wenn Sie nur einen faulen Verhalten wollten, Supplier selbst ist bereits in der Lage zu handeln faul wie get() nur dann ausgeführt wird, wenn aufgefordert, und nicht, wenn ein Supplier erstellt wird.

Wenn Sie eine Cachespeicherlogik wollen (nur einmal berechnen, und nur berechnen es erforderlich), könnten Sie so etwas wie folgt verwenden:

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; 
    } 
} 

Wenn Sie sicherstellen wollen, dass supplier.get() maximal einmal aufgerufen wird, können Sie könnte eine Synchronisation gelten:

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

Hier wird ein double-checked locking verwendet.

4

Lazy ist eine Unterklasse von Supplier und Sie versuchen, es anders zu casten.

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

zu

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

funktionieren sollte ändern.