Java 7中的获取或创建模式?
作者:互联网
我正在尝试编写一种通用功能,该功能可按需执行线程安全的可选惰性初始化.我不能使用标准模式,因为该值不是最终值,并且可能已经通过设置器设置了.
在Java 8中,我通过与供应商一起编写了一个通用的LazyInitializer解决了这一问题:
public class LazyInitializer<T> {
protected final Supplier<T> initializer;
protected AtomicReference<T> value = new AtomicReference<>();
public LazyInitializer(final Supplier<T> initializer) {
this.initializer = initializer;
}
public T get() {
T result = this.value.get();
if (result == null) {
this.value.compareAndSet(null, this.initializer.get());
result = this.value.get();
}
return result;
}
public void setValue(final T value) {
this.value.set(value);
}
}
然后,您将使用此类:
final LazyInitializer<List<String>> value = new LazyInitializer<>(ArrayList<String>::new);
这是线程安全的,可以处理setter,开销非常低,尤其是:需要很少的样板代码.
但是,现在我不得不使用Java 7,而且似乎找不到一个同样优雅的解决方案,因为Java 7无法使用Suppliers,因此需要编写许多难看的代码.同样,除非您提供确切的类,否则泛型不允许实例化它们,如果您使用泛型类值(例如ArrayList< String>),这是一个问题.
据我所知,我要么被迫编写丑陋的代码,要么被我的能力之外做反射魔术,或者有什么方法可以用Java 7中的优雅方式编写LazyInitializer类,而我却不见了?
编辑:使用来自Jorn Vernee的答案,我将类修改为与Java 7兼容,如下所示:
public class LazyInitializer<T> {
protected final Class<?> clazz;
protected AtomicReference<T> value = new AtomicReference<>();
public LazyInitializer(final Class<?> clazz) {
this.clazz = clazz;
}
public T get() {
T result = this.value.get();
if (result == null) {
this.value.compareAndSet(null, constructNew());
result = this.value.get();
}
return result;
}
public void setValue(final T value) {
this.value.set(value);
}
protected T constructNew() {
try {
return (T) clazz.newInstance();
} catch (InstantiationException | IllegalAccessException ex) {
throw new IllegalStateException(ex);
}
}
}
然后可以(再次)优雅地调用它,如下所示:
final LazyInitializer<List<String>> value = new LazyInitializer<>(ArrayList.class);
但是,此类不再能够验证所提供的类是否真正匹配(因为泛型),并且仅适用于默认构造函数.但这至少解决了我的情况.
解决方法:
关于lambdas / method refs的一件好事是,它减少了X的代码量.因此,如果您回头,当然,它将再次使X的代码量增加.如果您需要将任何代码包装在函子中,则匿名类是实现它的最佳方法.
还有另一种使用反射的效率较低,更骇人的方法.只要您按预期使用它,它就不会抛出异常.
您可以进行动态构造函数查找,您仍然需要Supplier类型:
interface Supplier<T> {
T get();
}
然后,您有一个工厂方法在运行时进行查找:
public static <T> Supplier<T> constructorLookup(Class<?> rawtype) {
try {
Constructor<?> cons = rawtype.getConstructor();
return new Supplier<T>() {
@SuppressWarnings("unchecked")
@Override
public T get() {
try {
return (T) cons.newInstance();
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
throw new IllegalStateException(e);
}
}
};
} catch (NoSuchMethodException | SecurityException e) {
throw new IllegalArgumentException(e);
}
}
结果代码如下所示:
LazyInitializer<List<String>> value
= new LazyInitializer<>(constructorLookup(ArrayList.class));
当前,这仅适用于默认构造函数,但也可以扩展为与参数一起使用.
标签:multithreading,lazy-initialization,java 来源: https://codeday.me/bug/20191111/2021598.html