2 种解决方案,一个函数 then 和一个对象(代码相同),线程安全,没有“if”,使用正确的类型传播(这里没有解决方案关心)。
很短。更好的惰性字段支持,由运行时处理,最终会使这段代码过时......
用法:
// object version : 2 instances (object and lambda)
final Lazy<Integer, RuntimeException> lazyObject = new LazyField<>(() -> 1);
// functional version : more efficient than object, 1 instance
// usage : wrap computed value using eval(arg), and set the lazy field with result
Lazy<Service, IOException> lazyFunc = lazyField(() -> this.lazyFunc = eval(new Service()));
// functional final version, as field is final this is less efficient than object :
// 2 instances one "if" and one sync (that could still be avoided...)
final Lazy<Integer, RuntimeException> finalFunc = lazyField(() -> eval(1));
// Here the checked exception type thrown in lambda can only be ServiceException
static Lazy<Integer, ServiceException> lazyTest = lazyField(() -> {throw new ServiceException();});
首先我定义了一个带有异常的 lambda:
@FunctionalInterface
interface SupplierWithException<T, E extends Exception> {
T get() throws E;
}
然后是惰性类型:
interface Lazy<T, E extends Exception> extends SupplierWithException<T, E> {}
功能版:
它直接返回一个最终获得更少内存占用的 lambda,如果不用于上面示例中的最终字段。
static <T, E extends Exception> Lazy<T, E> lazyField(Lazy<Lazy<T, E>, E> value) {
Objects.requireNonNull(value);
Lazy<T, E>[] field = new Lazy[1];
return () -> {
synchronized(field) {
if(field[0] == null)
field[0] = value.get();
return field[0].get();
}
};
}
static <T, E extends Exception> Lazy<T, E> eval(T value) {
return () -> value;
}
不能强制给出正确的值回调,至少它总是返回相同的结果但可能无法避免“如果”(如在最终字段的情况下)。
对象版本:
从外面完全安全。
public final class LazyField<T, E extends Exception> implements Lazy<T, E> {
private Lazy<T, E> value;
public LazyField(SupplierWithException<T, E> supplier) {
value = lazyField(() -> new Lazy<T, E>() {
volatile Lazy<T, E> memBarrier;
@Override
public T get() throws E {
value = memBarrier = eval(supplier.get());
}
});
}
@Override
public T get() throws E {
return value.get();
}
}
字段值的读取是无序的,但使用 volatile memBarrier 字段可确保写入该字段的值的顺序。如果在惰性值被有效设置后调用,则在此字段中设置的初始 lambda 也会返回初始化的惰性值。
享受