如果你愿意放弃参数的类型安全,你可以用Java 8和lambdas来记住任何函数:MethodHandle
public interface MemoizedFunction<V> {
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 <V> MemoizedFunction<V> memoizeFunction(Class<? super V> returnType, Method method) throws
IllegalAccessException {
final Map<ArgList, V> 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);
}
});
};
}
工作实例
这创建了一个包含函数的可变 arity lambda,并且在构造 lambda 后几乎与直接调用函数一样快(即,内部不会发生反射),因为我们使用的是 代替 。call(Object...args)
MethodHandle.invoke()
Method.invoke()
您仍然可以在没有 lambda(替换为匿名类)和 MethodHandles(替换为 Method.invoke)的情况下执行此操作,但是对于注重性能的代码来说,性能会受到损害,从而降低其吸引力。