2010-09-02 13 views

risposta

11

Memoizzazione è anche facile con la pianura semplice typesafe Java.

si può fare da zero con le seguenti classi riutilizzabili.

io uso questi come cache la cui durata di vita sono la richiesta su una webapp.

Ovviamente utilizzare Guava MapMaker se è necessaria una strategia di sfratto o più funzioni come la sincronizzazione.

Se è necessario memoizzare un metodo con molti parametri, è sufficiente mettere i parametri in un elenco con entrambe le tecniche e passare tale elenco come parametro singolo.

abstract public class Memoize0<V> { 
    //the memory 
    private V value; 
    public V get() { 
     if (value == null) { 
      value = calc(); 
     } 
     return value; 
    } 
    /** 
    * will implement the calculation that 
    * is to be remembered thanks to this class 
    */ 
    public abstract V calc(); 
} 

abstract public class Memoize1<P, V> { 
    //The memory, it maps one calculation parameter to one calculation result 
    private Map<P, V> values = new HashMap<P, V>(); 

    public V get(P p) { 
     if (!values.containsKey(p)) { 
      values.put(p, calc(p)); 
     } 
     return values.get(p); 
    } 

    /** 
    * Will implement the calculations that are 
    * to be remembered thanks to this class 
    * (one calculation per distinct parameter) 
    */ 
    public abstract V calc(P p); 
} 

E questo è usato come questo

Memoize0<String> configProvider = new Memoize0<String>() { 
     @Override 
     public String calc() { 
      return fetchConfigFromVerySlowDatabase(); 
     } 
    }; 
    final String config = configProvider.get(); 

    Memoize1<Long, String> usernameProvider = new Memoize1<Long, String>() { 
     @Override 
     public String calc(Long id) { 
      return fetchUsernameFromVerySlowDatabase(id); 
     } 
    }; 
    final String username = usernameProvider.get(123L); 
+0

Guava non è ancora stato approvato per il nostro ambiente, software finanziario ... – ranv01

+0

Guava non è ancora stato approvato per il nostro ambiente. Software bancario ... Ma questo lo farà. Limiterò comunque la dimensione della mappa per evitare perdite di memoria. Non mi preoccupo degli sfratti poiché questo sarà conservato solo durante l'invocazione di un metodo. – ranv01

+33

Mi piace il modo in cui il codice altamente testato non è approvato, ma qualcosa incollato su SO è :) –

14

Sì. Utilizzare caches da Guava.

Esempio:

import java.math.BigInteger; 

import com.google.common.base.Preconditions; 
import com.google.common.cache.CacheBuilder; 
import com.google.common.cache.CacheLoader; 
import com.google.common.cache.LoadingCache; 

public class Fibonacci { 
    private static final LoadingCache<Integer, BigInteger> CACHE 
      = CacheBuilder.newBuilder().build(CacheLoader.from(Fibonacci::fib)); 

    public static BigInteger fib(int n) { 
     Preconditions.checkArgument(n >= 0); 
     switch (n) { 
     case 0: 
      return BigInteger.ZERO; 
     case 1: 
      return BigInteger.ONE; 
     default: 
      return CACHE.getUnchecked(n - 1).add(CACHE.getUnchecked(n - 2)); 
     } 
    } 
} 
+7

MapMaker è ora obsoleto in favore di CacheBuilder: https://code.google.com/p/guava-libraries/wiki/MapMakerMigration – dzieciou

+2

@dzieciou Ho finalmente aggiornato il codice a qualcosa che funziona con l'ultimo Guava (18.0 a ora attuale della scrittura). E questa volta, è testato! –

16

Per Memoize funzioni senza parametri, utilizzare Guava di Suppliers.memoize(Supplier). Per le funzioni con parametri, utilizzare CacheBuilder.build(CacheLoader) con oggetti valore parametro come chiavi.

+0

Vedere anche https://github.com/google/guava/wiki/CachesExplained – Vadzim

+0

Esempio di Memoization: https://stackoverflow.com/questions/3636244/thread-safe-cache-of-one-object-in-java/ 3636791 # 3636791 – Vadzim

Problemi correlati