Java实例成员初始化抛出异常

发布于 2024-12-18 09:09:17 字数 1779 浏览 2 评论 0原文

假设我有以下类

public class A {
   private B b;
}

现在有一个用于创建 B 实例的工厂,但是如果我在声明行中设置 Ab,则创建者方法会抛出异常

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
}

,那么如果我在声明行中设置 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 中被破坏 双重检查锁定

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;
   }
}

那么,亲爱的耐心读者,我应该做什么?

换句话说,初始化包含对创建时可能引发异常的对象的引用的对象实例的最佳解决方案是什么?

Let us say I have the following class

public class A {
   private B b;
}

Now there is a factory for creating instances of B, but the creator method throws an exception

public class BCreatorFactory {
   public static createB() throws SomeException {
      // DO the intialization
      // ...
      return b;
}

if I set A.b in the declaration line then I would have no way of handling the exception

public class A {
   private B b = BCreatorFactory.createB() // BAD -> no way of dealing with the exception
}

if I set A.b within the constructor then I either have a "half baked" instance or again I throw an exception and force the calling code to handle a not properly initialized instance

public class A {
   private B b;

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

or

public class A {
   private B b;

   public A() throws SomeException { // BAD
      b = BCreatorFactory.createB();
   }
}

I could try to lazy init B's instance:

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;
   }
}

But the only way I can think of making it thread safe is via the known to be broken within java's JVMs 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;
   }
}

What then, dear patient reader, should I do?

In other words, what is the best solution to initializing an object instance that contains a reference to an object who's creation may throw an exception?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

圈圈圆圆圈圈 2024-12-25 09:09:17

这有什么问题吗?

public class A {
   private B b;

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

构造函数抛出异常并没有什么问题。

What's wrong with this?

public class A {
   private B b;

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

There's nothing wrong with a constructor throwing an exception.

内心激荡 2024-12-25 09:09:17

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

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

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

There is nothing wrong with a constructor throwing an exception. Many classes in the Java framework throw exception from the constructor. Its also fine to catch the exception inside the constructor so long as you have a way of handling and resolving the situation automatically. The point to checked exceptions in Java is so that you cannot just ignore the error condition and you have to handle it somewhere.

I throw an exception and force the calling code to handle a not properly initialized instance

The calling code will not have to deal with an improperly initialized instance, it will automatically go to the catch block where you should be doing something about the exception whether that be throwing it up, logging it, failing, etc.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文