2010-10-14 13 views
13

Mam kilka funkcji w moim kodzie, gdzie ma sens (wydaje się nawet obowiązkowe) do korzystania z memoization.Java: automatyczne zapamiętywanie

Nie chcę tego wdrażać ręcznie dla każdej funkcji osobno. Czy jest jakiś sposób (na przykład like in Python) Mogę po prostu użyć adnotacji lub zrobić coś innego, więc automatycznie otrzymam te funkcje tam, gdzie chcę?

Odpowiedz

10

Wiosna 3.1 zapewnia teraz @Cacheable annotation, który robi dokładnie to.

Jak sama nazwa wskazuje, służy do @Cacheable wytyczą metod, które są buforowalny - czyli metody, dla których wynik jest przechowywany w pamięci podręcznej, więc na kolejnych wezwań (z tymi samymi argumentami), wartość w pamięć podręczna jest zwracana bez konieczności wykonywania tej metody.

4

Nie wydaje mi się, aby istniała natywna implementacja zapamiętywania języka.

Ale można go łatwo wdrożyć, jako dekorator metody. Musisz zachować mapę: kluczem twojej mapy jest parametr, wartość wyniku.

Oto proste wdrożenie, dla metody jedno-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

Jak mogę go zrealizować w ogólny sposób jako dekorator mojej metody? – Albert

+0

@Albert: Jak Benoit stwierdził, nie ma natywnej implementacji tego (tj. Nie można tego zrobić w sposób ogólny bez hakowania w Javie), ponieważ rzeczownik dekoratora pythona używa pewnych "meta-informacji" dotyczących tej funkcji. To znaczy. w pytonie można pozwolić dekoratorowi zmienić pierwotną funkcję. Jest to - o ile mi wiadomo - niemożliwe w Javie. – phimuemue

+0

"możesz go łatwo wdrożyć, jako dekorator twojej metody." <- jak mogę to zrobić jako dekorator? Albo co masz na myśli? – Albert

6

natknąłem biblioteki memoization zwanego Tek271 który wydaje się użyć adnotacji do memoize funkcje jak opisujesz.

+0

Ah Widzę. Wygląda na to, że lib zapewnia sposób utworzenia obiektu opakowującego dla obiektu i automatycznie zapamiętuje funkcje, które zostały oznaczone do zapamiętania za pomocą adnotacji. – Albert

+1

Strona została przeniesiona i można ją teraz znaleźć pod adresem http://www.tek271.com/software/java/memoizer –

3

Można użyć interfejsu Function w guava biblioteki Google, aby łatwo osiągnąć to, co jesteś po:

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

powinien wydrukować:

dodanie 2 do: 1

Dodawanie 2 do: 2

Dodawanie 2 do: 3

dodanie 2 do: 4

Widać, że 2nd time memoizedAdd2 jest wywoływany (stosowany) do argumentów 2 i 1, the obliczenia w zastosowaniu nie są w rzeczywistości uruchomione, po prostu pobrano zapisane wyniki.

+0

Jest bardziej zbliżona do tego, co chcę, ale nadal jest zbyt szczegółowa. Czy można to uogólnić jeszcze bardziej, aby mogła przyjąć dowolną liczbę parametrów (a nie tylko jednego)? – Albert

+0

Klasa funkcji Guava skrapla wszystkie dane wejściowe w pojedynczy argument. Teraz typem tego argumentu może być Object [], skutecznie zezwalając na cokolwiek, ale zmniejszając skuteczność typowania. Lub, byłoby całkiem proste stworzenie nowego interfejsu Function2 wygenerowanego przez dla 2 argumentów, Funkcji3 itd. –

+0

W Guava klasa Dostawcy ma wbudowaną funkcję memoize i memoizeWithExpiration. – lbalazscs

0

Cyclops oferuje Memoisation dla funkcji, dostawców, Callables, orzeczników i metodami przedłużenie (Metodą referencje) (see javadoc)

np

Biorąc pod uwagę zmienną o nazwie, która zlicza czas, przez który faktycznie wywoływana jest nasza metoda, widzimy, że zapamiętana funkcja faktycznie wykonuje tę samą metodę tylko raz.

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; 
} 
Powiązane problemy