在Java中编写未经处理的清理代码时出现异常
假设我的类有一个获取资源的start()方法和一个释放资源的stop()方法。类的start方法可以调用成员对象的start()方法。如果某个成员对象的start()引发异常,我必须确保对start()成功的所有成员对象调用stop()
class X {
public X ()
{
a = new A();
b = new B();
c = new C();
d = new D();
}
public void start () throws Exception
{
try {
a.start();
} catch (Exception e) {
throw e;
}
try {
b.start();
} catch (Exception e) {
a.stop();
throw e;
}
try {
c.start();
} catch (Exception e) {
b.stop();
a.stop();
throw e;
}
try {
d.start();
} catch (Exception e) {
c.stop();
b.stop();
a.stop();
throw e;
}
}
public void stop ()
{
d.stop();
c.stop();
b.stop();
a.stop();
}
private A a;
private B b;
private C c;
private D d;
}
注意清理代码的二次增长。进行清理的最佳方式(最少的代码量)是什么?在C语言中,我可以很容易地通过函数底部的清理代码和“goto”跳转到适当的位置来实现这一点,但是Java没有goto。请注意,不允许对尚未启动()的对象调用stop()——我正在寻找与上述代码完全相同但更短的代码
到目前为止,我找到的唯一解决方案是使用布尔函数来记住启动的内容,如下所示:
public void start () throws Exception
{
boolean aStarted = false;
boolean bStarted = false;
boolean cStarted = false;
boolean dStarted = false;
try {
a.start();
aStarted = true;
b.start();
bStarted = true;
c.start();
cStarted = true;
d.start();
dStarted = true;
} catch (Exception e) {
if (dStarted) d.stop();
if (cStarted) c.stop();
if (bStarted) b.stop();
if (aStarted) a.stop();
throw e;
}
}
我知道“finally”和“try with resources”,但这两个词在这里似乎都不适用,因为如果没有例外,就不应该发布资源
顺便说一句,这不是关于我使用异常的问题,也不是关于我的程序设计的问题。这是专门针对初始化代码中出现故障时的清理
# 1 楼答案
如果您对线性展开的代码没有问题,那么可以使用如下结构的
start
方法:如果要启动/停止的项目确实不止几个,请像其他人建议的那样使用
List
# 2 楼答案
将你开始的东西添加到堆栈中,然后当你需要停止东西时,将所有东西从堆栈中弹出并停止
这要求您开始通过接口或子类拥有某种公共
stop()
,但我认为它们很可能已经拥有了# 3 楼答案
# 4 楼答案
虽然我很欣赏给出的所有想法,但我发现它们中没有一个适合广泛使用我的代码。特别是,基于堆栈/列表的方法存在问题,原因有两个:
即使对象没有启动,也可以调用stop()的想法也不适用于相同的原因——接口可能超出了程序员的控制范围
最后,我解决了这个问题,我发现它需要最少的样板文件。另一个好处是,即使对象没有启动,也可以调用生成的stop()方法(但这并不会使方法毫无意义,因为成员的start和stop函数可能不受程序员的控制)