2010-10-14 14 views
13

Tengo algunas funciones en mi código donde tiene mucho sentido (parece incluso obligatorio) utilizar la memoria.Java: memoria automática

No deseo implementarlo manualmente para cada función por separado. ¿Hay alguna forma (por ejemplo, like in Python) Puedo simplemente usar una anotación o hacer otra cosa, así que obtengo esto automáticamente en aquellas funciones donde lo quiero?

Respuesta

10

Spring 3.1 ahora proporciona un @Cacheable annotation, que hace exactamente esto.

Como el nombre implica, @Cacheable se utiliza para demarcar métodos que son cacheable - es decir, los métodos para los que el resultado se almacena en la memoria caché así sucesivamente invocaciones posteriores (con los mismos argumentos), el valor en el la memoria caché se devuelve sin tener que ejecutar realmente el método.

4

No creo que haya una implementación nativa del lenguaje de la memorización.

Pero puede implementarlo fácilmente, como decorador de su método. Debe mantener un Mapa: la clave de su Mapa es el parámetro, el valor es el resultado.

Aquí es una aplicación sencilla, para un método de un arg:

Map<Integer, Integer> memoizator = new HashMap<Integer, Integer>(); 

public Integer memoizedMethod(Integer param) { 

    if (!memoizator.containsKey(param)) { 
     memoizator.put(param, method(param)); 
    } 

    return memoizator.get(param); 
} 
+0

¿Cómo puedo implementarlo de manera general como decorador de mi método? – Albert

+0

@Albert: como dijo Benoit, no hay una implementación nativa de esto (es decir, no se puede hacer esto de forma general sin hackeo de Java), ya que las cosas de decodificador de Python utilizan cierta "metainformación" sobre la función. Es decir. es posible en Python dejar que el decorador altere la función original. Esto es, por lo que sé, imposible en Java. – phimuemue

+0

"puede implementarlo fácilmente, como decorador de su método". <- ¿cómo puedo hacerlo como decorador? ¿O qué quieres decir con eso? – Albert

6

me encontré con una biblioteca llamada memoization Tek271 que parece utilizar las anotaciones a memoize funciones que usted describe.

+0

Ah, ya veo. Parece que la lib proporciona una forma de crear un objeto envoltorio para su objeto y memoriza automáticamente aquellas funciones que fueron marcadas para la memorización a través de una anotación. – Albert

+1

La página se ha movido y ahora se puede encontrar en http://www.tek271.com/software/java/memoizer –

3

usted podría utilizar la interfaz Function en la biblioteca de Google guava lograr fácilmente lo que está buscando:

import java.util.HashMap; 
import java.util.Map; 

import com.google.common.base.Function; 

public class MemoizerTest { 
    /** 
    * Memoizer takes a function as input, and returns a memoized version of the same function. 
    * 
    * @param <F> 
    *   the input type of the function 
    * @param <T> 
    *   the output type of the function 
    * @param inputFunction 
    *   the input function to be memoized 
    * @return the new memoized function 
    */ 
    public static <F, T> Function<F, T> memoize(final Function<F, T> inputFunction) { 
    return new Function<F, T>() { 
     // Holds previous results 
     Map<F, T> memoization = new HashMap<F, T>(); 

     @Override 
     public T apply(final F input) { 
     // Check for previous results 
     if (!memoization.containsKey(input)) { 
      // None exists, so compute and store a new one 
      memoization.put(input, inputFunction.apply(input)); 
     } 

     // At this point a result is guaranteed in the memoization 
     return memoization.get(input); 
     } 
    }; 
    } 

    public static void main(final String[] args) { 
    // Define a function (i.e. inplement apply) 
    final Function<Integer, Integer> add2 = new Function<Integer, Integer>() { 
     @Override 
     public Integer apply(final Integer input) { 
     System.out.println("Adding 2 to: " + input); 
     return input + 2; 
     } 
    }; 

    // Memoize the function 
    final Function<Integer, Integer> memoizedAdd2 = MemoizerTest.memoize(add2); 

    // Exercise the memoized function 
    System.out.println(memoizedAdd2.apply(1)); 
    System.out.println(memoizedAdd2.apply(2)); 
    System.out.println(memoizedAdd2.apply(3)); 
    System.out.println(memoizedAdd2.apply(2)); 
    System.out.println(memoizedAdd2.apply(4)); 
    System.out.println(memoizedAdd2.apply(1)); 
    } 
} 

debe imprimir:

Adición de 2 a: 1

Agregar 2 a: 2

Adición de 2 a: 3

Adición de 2 a: 4

Se puede ver que el segundo el tiempo memorizadoAdd2 se llama (aplicado) a los argumentos 2 y 1, el el cálculo en la aplicación no se ejecutó realmente, simplemente obtuvo los resultados almacenados.

+0

Se acerca mucho más a lo que quiero, pero sigue siendo demasiado específico. ¿Es posible generalizar esto aún más para que pueda tomar cualquier cantidad de parámetros (y no solo uno)? – Albert

+0

La clase de función de guayaba condensa toda la entrada en un único argumento. Ahora, el tipo de ese argumento podría ser un Objeto [], permitiendo efectivamente lo que sea, pero reduciendo la efectividad de la verificación de tipo. O bien, sería bastante sencillo crear una nueva interfaz Function2 generada por para 2 argumentos, una Function3 , etc. –

+0

En Guava, la clase Suppliers tiene métodos incorporados memoize y memoizeWithExpiration. – lbalazscs

0

Cyclops ofrece Memoisation para las funciones, proveedores, callables, predicados y por métodos de extensión (mediante el método Referencias) (see javadoc)

por ejemplo

Dada una variable llamada que cuenta el número de veces que se llama realmente a nuestro método, podemos ver que la función memorada realmente ejecuta el método solo una vez.

int called = 0; 

cached = Memoise.memoiseQuadFunction(this::addAll); 

assertThat(cached.apply(1,2,3,4),equalTo(10)); 
assertThat(cached.apply(1,2,3,4),equalTo(10)); 
assertThat(called,equalTo(1)); 

private int addAll(int a,int b,int c, int d){ 
    called++; 
    return a+b+c+d; 
} 
Cuestiones relacionadas