2010-10-14 84 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; 
}