我一直在研究Java流量控制和异常处理,并且有这些普遍接受的规则:
除了一般规则,我试着遵循:
在某些情况下,这会造成混乱。我发现我在方法中捕获已检查的异常,并在任何地方返回布尔值,并不断检查连续的调用,做出类似这样的事情:
if(doA()){
if(doB()){
if(doC()){
// only here do I know it's good
}else{
// I know C failed
}
}else{
// I know B failed
}
}else{
// I know A failed
}
我得到5-6嵌套if-else在某些部分很深,而且非常难看。更不用说管理一堆布尔变量来跟踪哪些有效,哪些无效。
有什么建议吗?这会是'goto'可以接受的地方吗?
答案 0 :(得分:5)
您应该查看doA()
,doB()
和doC()
。如果它们不太可能失败,则在失败时抛出异常。
try {
doA();
doB();
doC();
} catch (FailureException e) {
// handle failure
}
不合理的失败案例比比皆是IOException
,IllegalParameterException
等。
如果他们有可能失败
if (!doA()) {
// handle A's failure
return;
}
if (!doB()) {
// handle B's failure
return;
}
if (!doC()) {
// handle C's failure
return;
}
合理失败的例子在Java中不那么重要了。一些例子包括read()
返回-1时,没有什么可读的。如果您的doA()
实际上更接近attemptA()
,那么可能会返回boolean
,表示尝试成功是合适的。考虑add(...)
界面中的addAll(...)
和Collections
,如果生成的true
被修改,则会返回Collection
。
传统的goto
在大多数语言中都不是一个好选择,因为在查看代码时,几乎不可能知道代码“来自何处”。在进入goto
之前缺乏对状态的了解使得在进入goto
块之前无法保证一致的环境。顺便说一下,这就是为什么传统的goto
在Java中不可用,只有有限的延续goto
。
要从嵌套不良的结构转换为嵌套较少的结构,请使用一些重构技术:
if(doA()){
if (doB()) {
if (doC()) {
// only here do I know it's good
} else {
// I know C failed
}
} else {
// I know B failed
}
} else {
// I know A failed
}
return;
相当于
if (doA()) {
if (doB()) {
if (doC()) {
// only here do I know it's good
} else {
// I know C failed
}
} else {
// I know B failed
}
return;
} else {
// I know A failed
return;
}
相当于
if (!doA()) {
// I know A failed
return;
} else {
if (doB()) {
if (doC()) {
// only here do I know it's good
} else {
// I know C failed
}
} else {
// I know B failed
}
return;
}
如果“我知道A失败”中的代码包含一个返回,那么您无需担心条件doA()
为真的代码属于下面的代码;所以你可以像下面这样推广下面的块:
if (!doA()) {
// I know A failed
return;
}
if (doB()) {
if (doC()) {
// only here do I know it's good
} else {
// I know C failed
}
} else {
// I know B failed
}
return;
答案 1 :(得分:1)
是。使用例外而不是返回代码。如果愿意,您可以将自己的异常包装起来。
在特殊条件下使用流量控制异常是完全合理的。通常的建议是避免将它们用于普通流量控制。
答案 2 :(得分:0)
我认为你的规则“不使用已检查的异常,除非客户希望恢复”是错误的。让调用者根本不恢复是很常见的,而是将异常传递给它的调用者,可能会将异常翻译成其他东西。
答案 3 :(得分:0)
我会使用The State Pattern。这样做可以使您的代码更多更容易阅读,因为您只能看到您可以从当前状态进入的状态。