Java实例成员初始化引发异常

Java实例成员初始化引发异常,java,multithreading,member-initialization,Java,Multithreading,Member Initialization,让我们假设我有下面的课程 public class A { private B b; } 现在有一个用于创建B实例的工厂,但是creator方法抛出一个异常 public class BCreatorFactory { public static createB() throws SomeException { // DO the intialization // ... return b; } public class A { priv

让我们假设我有下面的课程

public class A {
   private B b;
}
现在有一个用于创建B实例的工厂,但是creator方法抛出一个异常

public class BCreatorFactory {
   public static createB() throws SomeException {
      // DO the intialization
      // ...
      return b;
}
public class A {
   private B b = BCreatorFactory.createB() // BAD -> no way of dealing with the exception
}
如果我在声明行中设置了A.b,那么我将无法处理异常

public class BCreatorFactory {
   public static createB() throws SomeException {
      // DO the intialization
      // ...
      return b;
}
public class A {
   private B b = BCreatorFactory.createB() // BAD -> no way of dealing with the exception
}
如果我在构造函数中设置了A.b,那么我要么有一个“半成品”实例,要么再次抛出一个异常,并强制调用代码处理一个未正确初始化的实例

public class A {
   private B b;

   public A() {
      try {
         b = BCreatorFactory.createB();
      }
      catch (SomeException se) {
      // Do something, perhaps try to recover ? <- IMO also BAD
      }
   }
}
我可以尝试惰性初始化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中已知的被破坏的双重检查锁定

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;
   }
}
那么,亲爱的耐心读者,我该怎么办


换句话说,初始化包含对正在创建的对象的引用的对象实例的最佳解决方案是什么?这有什么问题

public class A {
   private B b;

   public A() throws SomeException { // BAD -- *no it's not*
      b = BCreatorFactory.createB();
   }
}

构造函数抛出异常没有什么错。

这有什么错

public class A {
   private B b;

   public A() throws SomeException { // BAD -- *no it's not*
      b = BCreatorFactory.createB();
   }
}

构造函数抛出异常没有错。

构造函数抛出异常没有错。Java框架中的许多类从构造函数抛出异常。只要您有一种自动处理和解决情况的方法,在构造函数中捕获异常也是很好的。Java中检查异常的要点是,您不能忽略错误条件,必须在某个地方处理它

我抛出一个异常并强制调用代码处理未正确初始化的实例

public class A {
   private B b;

   public A() {
      try {
         b = BCreatorFactory.createB();
      }
      catch (SomeException se) {
      // Do something, perhaps try to recover ? <- IMO also BAD
      }
   }
}

调用代码不必处理未正确初始化的实例,它将自动转到catch块,您应该在那里对异常进行处理,无论是抛出异常、记录异常、失败等等。

构造函数抛出异常没有什么错。Java框架中的许多类从构造函数抛出异常。只要您有一种自动处理和解决情况的方法,在构造函数中捕获异常也是很好的。Java中检查异常的要点是,您不能忽略错误条件,必须在某个地方处理它

我抛出一个异常并强制调用代码处理未正确初始化的实例

public class A {
   private B b;

   public A() {
      try {
         b = BCreatorFactory.createB();
      }
      catch (SomeException se) {
      // Do something, perhaps try to recover ? <- IMO also BAD
      }
   }
}

调用代码不必处理未正确初始化的实例,它将自动转到catch块,在那里您应该对异常执行一些操作,无论是抛出异常、记录异常、失败,等等。

我不清楚为什么你认为让A的构造函数抛出
SomeException
在这里是件坏事。为什么你认为抛出B的异常是件坏事?当抛出异常时,你预计会发生什么?如果不知道这一点,就很难知道该怎么办。另外,通过使用
volatile
,双重检查锁定在JDK5+下不会像以前那样被破坏,我不清楚为什么你认为让A的构造函数抛出某个异常是件坏事。为什么你认为抛出B的异常是件坏事?当抛出异常时,你预计会发生什么?如果不知道这一点,就很难知道该怎么办。另外,通过使用
volatile
,双重检查锁定在JDK5+下不会像以前那样被破坏,