【问题标题】:What are the different techniques for memoization in Java? [closed]Java 中有哪些不同的记忆技术? [关闭]
【发布时间】:2011-04-07 03:05:53
【问题描述】:

我知道这个http://onjava.com/pub/a/onjava/2003/08/20/memoization.html,但还有别的吗?

【问题讨论】:

  • 此示例通过代理对对象的所有方法进行记忆。但典型的记忆是当时的一项功能。当你不想记住一个对象的所有方法时,这种代理技术会很烦人。

标签: java memoization


【解决方案1】:

要记住不带参数的函数,请使用 Guava 的Suppliers.memoize(Supplier)。对于带参数的函数,使用CacheBuilder.build(CacheLoader),带参数值对象作为键。

【解决方案2】:

是的。使用Guava 中的caches

例子:

import java.math.BigInteger;

import com.google.common.base.Preconditions;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

public class Fibonacci {
    private static final LoadingCache<Integer, BigInteger> CACHE
            = CacheBuilder.newBuilder().build(CacheLoader.from(Fibonacci::fib));

    public static BigInteger fib(int n) {
        Preconditions.checkArgument(n >= 0);
        switch (n) {
        case 0:
            return BigInteger.ZERO;
        case 1:
            return BigInteger.ONE;
        default:
            return CACHE.getUnchecked(n - 1).add(CACHE.getUnchecked(n - 2));
        }
    }
}

【讨论】:

【解决方案3】:

使用简单的类型安全 Java 也可以轻松实现记忆。

您可以使用以下可重用类从头开始。

我将它们用作缓存,其生命周期是 web 应用程序上的请求。

如果您需要驱逐策略或同步等更多功能,当然可以使用 Guava MapMaker

如果您需要记忆具有许多参数的方法,只需将参数放在具有两种技术的列表中,然后将该列表作为单个参数传递。

abstract public class Memoize0<V> {
    //the memory
    private V value;
    public V get() {
        if (value == null) {
            value = calc();
        }
        return value;
    }
    /**
     * will implement the calculation that 
     * is to be remembered thanks to this class
     */
    public abstract V calc();
}

abstract public class Memoize1<P, V> {
    //The memory, it maps one calculation parameter to one calculation result
    private Map<P, V> values = new HashMap<P, V>();

    public V get(P p) {
        if (!values.containsKey(p)) {
            values.put(p, calc(p));
        }
        return values.get(p);
    }

    /**
     * Will implement the calculations that are
     * to be remembered thanks to this class
     * (one calculation per distinct parameter)
     */
    public abstract V calc(P p);
 }

这个是这样使用的

    Memoize0<String> configProvider = new Memoize0<String>() {
        @Override
        public String calc() {
            return fetchConfigFromVerySlowDatabase();
        }
    };
    final String config = configProvider.get();

    Memoize1<Long, String> usernameProvider = new Memoize1<Long, String>() {
        @Override
        public String calc(Long id) {
            return fetchUsernameFromVerySlowDatabase(id);
        }
    };
    final String username = usernameProvider.get(123L);

【讨论】:

  • Guava 尚未获准用于我们的环境、财务软件...
  • Guava 尚未获准用于我们的环境。银行软件……但这可以。但是,我将限制地图的大小以避免内存泄漏。我不关心驱逐,因为这只会在调用一种方法时保留。
  • 我喜欢经过高度测试的代码未被批准的方式,但粘贴在 SO 上的内容是 :)
  • 谨慎使用 Memoize0 示例,因为它不是线程安全的。在竞争条件下,多个线程可能会多次调用 calc() 方法。 Guava 的实现是线程安全的,一旦初始化就在 get() 上无锁,因为它使用双重检查锁定:github.com/google/guava/blob/master/guava/src/com/google/common/…
  • 看起来MapMaker 不存在(不再存在)。请改用CacheBuilder
猜你喜欢
  • 1970-01-01
  • 2011-08-16
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
  • 1970-01-01
  • 2020-08-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多