2010-10-14 12 views
13

Ich habe ein paar Funktionen in meinem Code, wo es sehr sinnvoll ist, Memoization zu verwenden (scheint sogar obligatorisch).Java: automatische Memoisierung

Ich möchte das nicht manuell für jede Funktion separat implementieren. Gibt es einen Weg (zum Beispiel like in Python) kann ich einfach eine Anmerkung verwenden oder etwas anderes tun, damit ich das automatisch auf jene Funktionen bekomme, wo ich es haben will?

Antwort

10

Feder 3.1 bietet nun eine @Cacheable annotation, die genau dies tut.

Wie der Name schon sagt, wird @Cacheable Methoden abgrenzen, die im Cache gespeichert werden - das heißt, das Ergebnis Methoden, für die in den Cache so auf nachfolgenden Aufrufen gespeichert wird (mit den gleichen Argumenten), wird der Wert in der Cache wird zurückgegeben, ohne dass die Methode tatsächlich ausgeführt werden muss.

4

Ich glaube nicht, dass es eine spracheigene Implementierung von Memoization gibt.

Aber Sie können es leicht implementieren, als Dekorateur Ihrer Methode. Sie müssen eine Map pflegen: Der Schlüssel Ihrer Map ist der Parameter, der Wert das Ergebnis.

Hier ist eine einfache Implementierung für eine argument Methode:

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

Wie kann ich es als Dekorateur meiner Methode allgemein implementieren? – Albert

+0

@Albert: Wie Benoit sagte, gibt es keine native Implementierung von diesem (d. H. Sie können dies nicht ohne Java-Hacking machen), da der Python-Decorator-Kram einige "Meta-Informationen" über die Funktion verwendet. I.e. In Python ist es möglich, dass der Dekorateur die ursprüngliche Funktion ändert. Dies ist - soweit ich weiß - in Java nicht möglich. – phimuemue

+0

"Sie können es leicht implementieren, als Dekorateur Ihrer Methode." <- wie kann ich das als Dekorateur machen? Oder was meinst du damit? – Albert

6

ich auf eine memoization Bibliothek kam Tek271 genannt, die Anmerkungen zu verwenden, erscheint Funktionen memoize wie Sie beschreiben.

+0

Ah ich sehe. Es scheint, dass die lib eine Möglichkeit bietet, ein Wrapper-Objekt für Ihr Objekt zu erstellen, und es automatisch die Funktionen memotisiert, die für die Memoisierung über eine Annotation markiert wurden. – Albert

+1

Die Seite ist umgezogen und kann nun unter http://www.tek271.com/software/java/memoizer gefunden werden. –

3

Sie konnten die Function Schnittstelle in den Google-guava Bibliothek verwenden, um leicht zu erreichen, was Sie wollen:

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

drucken Sollte:

Hinzufügen von 2 bis: 1

Hinzufügen von 2 zu: 2

Hinzufügen von 2 bis: 3

Hinzufügen von 2 bis: 4

können Sie, dass der zweite sehen Zeit memoizedAdd2 wird auf die Argumente 2 und 1, (.) angewendet Berechnung in der Anwendung ist nicht wirklich ausgeführt, es hat nur die gespeicherten Ergebnisse abgerufen.

+0

Kommt näher dran, was ich will, aber immer noch zu spezifisch. Ist es möglich, dies noch mehr zu verallgemeinern, so dass es beliebig viele Parameter (und nicht nur eine) annehmen kann? – Albert

+0

Die Guava-Funktionsklasse verdichtet alle Eingaben zu einem einzigen Argument. Nun könnte der Typ dieses Arguments ein Objekt [] sein, was effektiv erlaubt, was auch immer, aber die Effektivität der Typüberprüfung verringert. Oder es wäre ziemlich einfach, eine neue Function2-Schnittstelle zu erstellen, generalisiert durch für 2 Argumente, eine Funktion3 usw. –

+0

In Guava hat die Suppliers-Klasse eingebaute memoize- und memoizeWithExpiration-Methoden. – lbalazscs

0

Cyclops bietet Memoisation für Funktionen, Lieferanten, Callables, Prädikate und durch Erweiterungsmethoden (via Method References) (see javadoc)

Z.B.

Wenn eine Variable aufgerufen wird, die die Anzahl der Zeit zählt, die unsere Methode tatsächlich aufgerufen wird, können wir sehen, dass die Memo-Funktion die Methode tatsächlich nur einmal ausführt.

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