Java实例成员初始化抛出异常
假设我有以下类
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这有什么问题吗?
构造函数抛出异常并没有什么问题。
What's wrong with this?
There's nothing wrong with a constructor throwing an exception.
构造函数抛出异常并没有什么问题。 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.
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.