次のクラスがあるとしましょう
public class A {
private B b;
}
B のインスタンスを作成するためのファクトリがありますが、作成者メソッドは例外をスローします。
public class BCreatorFactory {
public static createB() throws SomeException {
// DO the intialization
// ...
return b;
}
宣言行に Ab を設定すると、例外を処理する方法がありません
public class A {
private B b = BCreatorFactory.createB() // BAD -> no way of dealing with the exception
}
コンストラクター内で Ab を設定すると、「半分焼かれた」インスタンスが作成されるか、再び例外がスローされ、呼び出し元のコードが適切に初期化されていないインスタンスを処理するように強制されます。
public class A {
private B b;
public A() {
try {
b = BCreatorFactory.createB();
}
catch (SomeException se) {
// Do something, perhaps try to recover ? <- IMO also BAD
}
}
}
また
public class A {
private B b;
public A() throws SomeException { // BAD
b = BCreatorFactory.createB();
}
}
B のインスタンスを遅延初期化することができます。
public class A {
private B b;
public B getB() throws SomeException {
if (b == null) {
b = BCreatorFactory.createB(); // BAD -> not thread safe -> can result in redundant createB() invocations
}
return b;
}
}
しかし、スレッドセーフにする唯一の方法は、Java の JVM 内で壊れていることが知られているDouble-Checked Lockingを使用することです。
public class A {
private B b;
public B getB() throws SomeException {
if (b == null) {
synchronized(this) {
if (b == null) {
b = BCreatorFactory.createB(); // BAD -> not really thread safe -> broken
}
}
}
return b;
}
}
では、辛抱強い読者の皆さん、私は何をすべきでしょうか?
言い換えれば、作成時に例外をスローする可能性のあるオブジェクトへの参照を含むオブジェクト インスタンスを初期化するための最良の解決策は何ですか?