2010-09-02 24 views

Respuesta

11

memoization es también fácil con una simple typesafe llanura de Java.

Puede hacerlo desde cero con las siguientes clases reutilizables.

Utilizo estos como cachés cuya vida útil es la solicitud en una aplicación web.

Por supuesto, use la Guava MapMaker si necesita una estrategia de desalojo o más funciones como la sincronización.

Si necesita memorizar un método con muchos parámetros, simplemente coloque los parámetros en una lista con ambas técnicas, y pase esa lista como el parámetro único.

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

Y esto se utiliza como esto

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

La guayaba todavía no está aprobada para nuestro entorno, el software financiero ... – ranv01

+0

La guayaba todavía no está aprobada para nuestro medio ambiente. Software bancario ... Pero esto servirá. Sin embargo, limitaré el tamaño del mapa para evitar pérdidas de memoria. No me preocupan los desalojos, ya que esto se conservará solo durante la invocación de un método. – ranv01

+33

Me gusta la forma en que el código altamente probado no está aprobado, pero algo pegado en SO es :) –

14

Sí. Use caches de Guava.

Ejemplo:

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 ahora está en desuso en favor de CacheBuilder: https://code.google.com/p/guava-libraries/wiki/MapMakerMigration – dzieciou

+2

@dzieciou Finalmente he actualizado el código a algo que funciona con la última guayaba (18.0 en hora actual de escritura). ¡Y esta vez, está probado! –

16

Para memoize funciones sin parámetros, el uso de guayaba Suppliers.memoize(Supplier). Para funciones con parámetros, use CacheBuilder.build(CacheLoader) con objetos de valor de parámetro como claves.

+0

Véase también https://github.com/google/guava/wiki/CachesExplained – Vadzim

+0

Ejemplo de memoización: https://stackoverflow.com/questions/3636244/thread-safe-cache-of-one-object-in-java/ 3636791 # 3636791 – Vadzim

Cuestiones relacionadas