Памятка в Java - PullRequest
       1

Памятка в Java

2 голосов
/ 22 ноября 2011

Хорошо, поэтому в C # я мог бы написать:

public class Memorizer<K,TRes>
{
    private Dictionary<K,TRes> _mem;
    private Func<K,TRes> _function

    public Memorizer (Func<K,TRes> function)
    {
        _function = function;
        _mem= new Dictionary<K,TRes>();
    }

    public TRes Call(K arg)
    {
        if (mem.ContainsKey(arg)
        {
            return _mem[arg];
        }
        else
        {
            TRes ret=_function(arg);
            _mem[arg] = ret;
            return ret;
        }
    }
}

Что можно использовать для получения очевидных выгод:

public class FactorialCalculator()
{
    private Memorizer<ushort, ulong> _memorizedFactorial;
    public FactorialCalculator()
    {
        _memorizedFactorial = new Memorizer<ushort, ulong> (innerFactorial);
    }

    private ulong innerFactorial(ushort x)
    {
        return (x=0) ? 1 : x*Factorial(x-1)
    }

    public ulong factorial(ushort x)
    {
        _memorizedFactorial.Call(x);
    }

}

Я уверен, что это можно сделать более общим и элегантным. И я знаю, что у меня будут исключения переполнения, если x> 20. (И у меня там тоже могут быть ошибки типов) Но, надеюсь, я высказал свою точку зрения: я могу создать класс, который может удовлетворить потребности в запоминании чисто математических функций (т.е. детерминированных, не имеющих побочных эффектов функций) и получите замечательный прирост производительности.

Как я могу сделать подобное в Java?

Ответы [ 4 ]

3 голосов
/ 11 июня 2015

В Java 8 вы можете использовать computeIfAbsent для создания заметок:

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

public class FactorialCalculator {

public static void main(String[] args) {

    Function<Integer, Long> factorialFunction = x -> {
        System.out.println("Calculating factorial for " + x);
        long fact = 1;
        for (int i = 1; i <= x; i++) {
            fact *= i;
        }
        return fact;
    };

    Function<Integer, Long> memoziedFactorialFunction = memoise(factorialFunction);

    System.out.println(memoziedFactorialFunction.apply(5));
    System.out.println(memoziedFactorialFunction.apply(5));
    System.out.println(memoziedFactorialFunction.apply(5));
    System.out.println(memoziedFactorialFunction.apply(5));
    System.out.println(memoziedFactorialFunction.apply(6));
    System.out.println(memoziedFactorialFunction.apply(6));

}

public static <X, Y> Function<X, Y> memoise(Function<X, Y> fn) {
    Map<X, Y> pp = new ConcurrentHashMap<X, Y>();
    return (a) -> pp.computeIfAbsent(a, fn);
}

}

Результат:

Calculating factorial for 5
120
120
120
120
Calculating factorial for 6
720
720

Подробнее здесь http://rdafbn.blogspot.ie/2015/06/memoize-functions-in-java-8.html

Наконец, вы можете использовать библиотеку cyclops для удаления стандартного кода создания универсальных методов memoize (см. http://static.javadoc.io/com.aol.cyclops/cyclops-functions/4.0.2/com/aol/cyclops/functions/Memoise.html)

2 голосов
/ 22 ноября 2011

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

public interface ReturnFunction<K, V> {
    public V getValue(K k);
}

Теперь вы можете установить innerFactorial для типа данных.

public ReturnFunction<Short, Long> innerFactorial = new ReturnFunction<Short, Long>(){
    public Long getValue(Short x){
        return (x=0) ? 1 : x*Factorial(x-1);
    }
};

Это позволяет вам передавать innerFactorial в качестве типа данных:

_memoizedFactorial = new Memorizer<Short, Long> (innerFactorial);

И для вызова функции вы напишите это:

long someLong = _memoizedFactorial.getValue(someShort);

Кроме того, в Java не используйте заглавные буквы или имена методов. Это не стандартно и затрудняет чтение кода.

2 голосов
/ 22 ноября 2011

Проверьте кеш в Guava. Вот для чего это.

0 голосов
/ 22 ноября 2011

Вы не можете создать универсальную карту из <short, ulong> в Java, потому что параметры универсального типа привязываются только к ссылочным типам. Вам придется сделать это <Short, Long>, что включает в себя обертывание примитивов и может внести некоторые накладные расходы в вашу памятку.

Кроме того, перевод на Java довольно прост. Просто имейте в виду, что вы можете запоминать только те типы, которые предоставляют полезные реализации equals и hashCode, и вам нужно использовать ограниченную по размеру, поточно-ориентированную таблицу слабых ключей, например, предоставленную MapMaker .

...