Java: автоматическое запоминание - PullRequest
14 голосов
/ 14 октября 2010

В моем коде есть несколько функций, в которых имеет смысл (кажется, даже обязательно) использовать памятку.

Я не хочу реализовывать это вручную для каждой функции отдельно. Есть ли какой-нибудь способ (например, как в Python ), я могу просто использовать аннотацию или сделать что-то еще, чтобы я автоматически получал это на тех функциях, где я хочу?

Ответы [ 5 ]

12 голосов
/ 18 марта 2012

Spring 3.1 теперь предоставляет аннотацию @Cacheable , которая именно это и делает.

Как видно из названия, @Cacheable используется для разграничения кешируемых методов - чтото есть методы, для которых результат сохраняется в кеше, поэтому при последующих вызовах (с теми же аргументами) значение в кеше возвращается без фактического выполнения метода.

6 голосов
/ 14 октября 2010

Я столкнулся с библиотекой напоминаний Tek271 , которая, кажется, использует аннотации для запоминания функций, которые вы описываете.

4 голосов
/ 14 октября 2010

Вы можете использовать интерфейс Function в библиотеке Google 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

3

Добавление 2 к: 2

4

Добавление 2 к: 3

5

4

Добавление 2 к: 4

6

3

Вы можете видеть, что во второй раз вызывается memoizedAdd2 (применяется)) к аргументам 2 и 1 вычисление в приложении фактически не выполняется, оно просто извлекает сохраненные результаты.

4 голосов
/ 14 октября 2010

Я не думаю, что есть языковая реализация мемоизации.

Но вы можете легко реализовать это как декоратор вашего метода. Вы должны поддерживать карту: ключ вашей карты - это параметр, значение - результат.

Вот простая реализация для метода с одним аргументом:

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 голосов
/ 11 июня 2015

Циклоп предлагает памятку для функций, поставщиков, вызовов, предикатов и методов расширения (через ссылки на методы) ( см. Javadoc )

например.

Учитывая переменную, которая называется, которая подсчитывает количество раз, когда наш метод фактически вызывается, мы можем видеть, что запомненная функция фактически выполняет метод только один раз.

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