Saltar al contenido

Método de memorización de Java

Este dilema se puede resolver de diferentes maneras, pero en este caso te damos la resolución más completa para nosotros.

Solución:

En Java 8 puedes usar ConcurrentHashMap.computeIfAbsent:

Map cache = new ConcurrentHashMap<>();

Integer addOne(Integer x) 
    return cache.computeIfAbsent(x -> x + 1);

DZone tiene un buen tutorial que proporciona una solución que funcionará para cualquier método:

El Memoizer la clase es bastante simple:

public class Memoizer 

  private final Map cache = new ConcurrentHashMap<>();

  private Memoizer() 

  private Function doMemoize(final Function function) 
    return input -> cache.computeIfAbsent(input, function::apply);
  

  public static  Function memoize(final Function function) 
    return new Memoizer().doMemoize(function);
  

Usar esta clase también es extremadamente simple:

Integer longCalculation(Integer x) 
  try 
    Thread.sleep(1_000);
   catch (InterruptedException ignored) 
  
  return x * 2;

Function f = this::longCalculation;
Function g = Memoizer.memoize(f);

public void automaticMemoizationExample() 
  long startTime = System.currentTimeMillis();
  Integer result1 = g.apply(1);
  long time1 = System.currentTimeMillis() - startTime;
  startTime = System.currentTimeMillis();
  Integer result2 = g.apply(1);
  long time2 = System.currentTimeMillis() - startTime;
  System.out.println(result1);
  System.out.println(result2);
  System.out.println(time1);
  System.out.println(time2);

ejecutando el automaticMemoizationExample método producirá el siguiente resultado:

2
2
1000
0

Puedes memorizar cualquier función con Java 8 MethodHandles y lambdas si está dispuesto a renunciar a la seguridad de tipos en los parámetros:

public interface MemoizedFunction 
    V call(Object... args);


private static class ArgList 
    public Object[] args;

    @Override
    public boolean equals(Object o) 
        if (this == o) 
            return true;
        
        if (!(o instanceof ArgList)) 
            return false;
        

        ArgList argList = (ArgList) o;

        // Probably incorrect - comparing Object[] arrays with Arrays.equals
        return Arrays.equals(args, argList.args);
    

    @Override
    public int hashCode() 
        return args != null ? Arrays.hashCode(args) : 0;
    


public static  MemoizedFunction memoizeFunction(Class returnType, Method method) throws
                                                                                                  IllegalAccessException 
    final Map memoizedCalls = new HashMap<>();
    MethodHandles.Lookup lookup = MethodHandles.lookup();
    MethodHandle methodHandle = lookup.unreflect(method)
                                      .asSpreader(Object[].class, method.getParameterCount());
    return args -> 
        ArgList argList = new ArgList();
        argList.args = args;
        return memoizedCalls.computeIfAbsent(argList, argList2 -> 
            try 
                //noinspection unchecked
                return (V) methodHandle.invoke(args);
             catch (Throwable throwable) 
                throw new RuntimeException(throwable);
            
        );
    ;

Ejemplo de trabajo

Esto crea una lambda de aridad variable que encierra la función y es casi tan rápido como llamar a la función directamente (es decir, no ocurre ningún reflejo dentro de call(Object...args)) después de construir la lambda ya que estamos usando MethodHandle.invoke() en vez de Method.invoke().

Todavía puede hacer esto sin lambdas (reemplazar con clases anónimas) y MethodHandles (reemplazar con Method.invoke), pero habrá penalizaciones de rendimiento que harán que esto sea menos atractivo para el código consciente del rendimiento.

Comentarios y valoraciones de la guía

Agradecemos que quieras añadir valor a nuestro contenido asistiendo con tu veteranía en las interpretaciones.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *