我一直在研究Java流量控制和异常处理,并且有这些普遍接受的规则:
>不要对流量控制使用异常处理
>避免检查异常,除非客户端希望恢复(这是一种很好的方式,说你强迫客户端处理异常,所以他们不妨尝试从中恢复?)
除了一般规则,我试着遵循:
>如果doSomething()无法“做某事”,应该让调用者意识到这一点
>方法应该关注做一件事
在某些情况下,这会造成混乱.我发现我在方法中捕获已检查的异常并在每个地方返回布尔值并不断检查连续的调用,制作如下所示的内容:
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’可以接受的地方吗?
解决方法:
您应该查看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(),那么可能返回一个布尔值,指示尝试成功是合适的.考虑在Collections界面中添加(…)和addAll(…),如果生成的Collection被修改,它们将返回true.
传统的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;