2010-10-14 82 views
13

我在我的代碼中有幾個函數,它使用memoization有很大的意義(甚至是強制性的)。Java:自動記憶

我不想爲每個功能單獨手動實現。是否有某種方法(例如like in Python)我可以只使用一個註釋或做其他事情,這樣我就可以在需要它的那些函數上自動獲取它?

回答

10

Spring 3.1現在提供了一個@Cacheable annotation,它完全是這樣。

顧名思義,@Cacheable用於區分是緩存的方法 - 那就是,方法對他們來說,結果被存入緩存,以便在後續調用(使用相同的參數),在價值緩存被返回而不必實際執行該方法。

4

我不認爲有一種語言本地實現memoization。

但是你可以很容易地實現它,作爲你的方法的裝飾器。你必須保持一個Map:你的Map的關鍵是參數,值是結果。

下面是一個簡單的實現,對於一個帶參數的方法:

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

我怎樣才能以通用的方式實現它作爲我的方法的裝飾器? – Albert 2010-10-14 15:38:49

+0

@Albert:作爲伯努瓦表示,沒有本地實現這一點(即你不能在沒有Java的黑客一般的方式做到這一點),因爲蟒蛇裝飾材料使用了一些「元信息」有關的功能。即python可以讓修飾器修改原始函數。這是 - 據我所知 - 在Java中不可能。 – phimuemue 2010-10-14 15:44:41

+0

「你可以很容易地實現它,作爲你的方法的裝飾器。」 < - 我怎樣才能做到裝飾者?或者你是什麼意思? – Albert 2010-10-14 15:46:11

6

我遇到稱爲Tek271一個記憶化庫出現使用註釋爲您介紹到memoize的功能來。

+0

啊我明白了。看起來,lib提供了一種爲對象創建包裝器對象的方法,它會自動記憶通過註釋標記爲備忘錄的那些函數。 – Albert 2010-10-14 16:26:51

+1

頁面已移動,並且現在可以在http://www.tek271.com/software/java/memoizer – 2011-05-02 21:10:46

3

您可以使用Function接口谷歌的guava庫來輕鬆實現你以後:

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

應打印:

將2:1

將2添加到:2

添加2〜3

添加2至4

你可以看到,第二時間memoizedAdd2被調用(應用)到參數2和1,應用程序中的計算實際上並未運行,只是取得了存儲的結果。

+0

來得更接近我想要什麼,但還是太具體被發現。是否有可能對此進行更廣義的描述,以便可以使用任意數量的參數(而不僅僅是一個)? – Albert 2010-10-15 09:12:38

+0

Guava的Function類將所有輸入濃縮爲一個參數。現在,這個論點的類型可以是一個Object [],它可以有效地允許任何事情,但會降低類型檢查的有效性。或者說,這將是非常簡單的創建由 generisized新功能2接口,2個參數,一個功能3 等 – 2010-10-15 12:59:10

+0

番石榴的供應商類具有內置的memoize的和memoizeWithExpiration方法。 – lbalazscs 2015-03-20 00:04:05

0

Cyclops提供Memoisation的功能,供應商,可調用,謂詞和擴展方法(通過方法引用)(see javadoc

例如

給定一個所謂的可變計數的時間我們的方法其實就是所謂的號碼,我們可以看到memoised功能實際上執行的方法只有一次。

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