私は、オンデマンドでスレッドセーフなオプションの遅延初期化を行い、一般的な機能を記述しようとしています。値は最終的なものではなく、すでにセッターを介して設定されている可能性があるので、標準パターンは使用できません。Java 7でパターンを取得または作成しますか?
final LazyInitializer<List<String>> value = new LazyInitializer<>(ArrayList<String>::new);
これは、スレッドセーフで、処理することができます:
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);
}
}
あなたは、このように、このクラスを使用します。
は、Java 8で、私は、サプライヤーとのLazyInitializer
ジェネリックを書くことでことを解決しましたsettersは、オーバーヘッドが非常に低く、特に:定型コードをほとんど必要としません。
ArrayList<String>
のような)ジェネリッククラス値を使用する場合に問題となる、あなたは正確なクラスを提供しない限り、それらをインスタンス化することはできません。
私が知る限り、醜いコードを書いたり、私の能力を超えてリフレクションマジックを書いたりすることができますか?または、LazyInitializer
クラスをJava 7のエレガントな方法で書く方法がありますか?
編集:次のようにジョーンVerneeからの回答を使用するには、私は、Java 7で動作するようにクラスを変更:
final LazyInitializer<List<String>> value = new LazyInitializer<>(ArrayList.class);
:そしてエレガントに、このように呼ばれる(再び)することができ
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);
}
}
}
しかし提供されたクラスは、実際に(ジェネリックので)と一致し、それが唯一のデフォルトコンストラクタで動作している場合、このクラスは、もはや確認することはできません。しかし、少なくともそれは私の場合を解決する。
私は間違っているか、あなたのJava8サンプルコードの最初の 'this.value.get()'とif節をスキップしてもよいですか? – Alexander
'value == null 'の場合、値は初期値に設定する必要があります。だから、それをスキップすることはできません。 – TwoThe
@TwoThe私は間違っているか、コードが実際に複数回サプライヤの実行をトリガすることができますか? 'compareAndSet'のためのパラメータ評価は関数自身のために原子的ではないので。 – chimmi