如何在Java中管理复杂的流控制?

tim*_* p. 3 java controls exception-handling flow

我一直在研究Java流量控制和异常处理,并且有这些普遍接受的规则:

  1. 不要将异常处理用于流控制
  2. 避免检查异常,除非客户端希望恢复(这是一种很好的方式,说你强迫客户端处理异常,所以他们不妨尝试从中恢复?)

除了一般规则,我试着遵循:

  1. 如果doSomething()无法"做某事",应该让调用者意识到这一点
  2. 方法应该关注做一件事

在某些情况下,这会造成混乱.我发现我在方法中捕获已检查的异常并在每个地方返回布尔值并不断检查连续的调用,制作如下所示的内容:

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
}
Run Code Online (Sandbox Code Playgroud)

我得到5-6嵌套if-else在某些部分很深,而且非常难看.更不用说管理一堆布尔变量来跟踪哪些有效,哪些无效.

有什么建议?这会是'goto'可以接受的地方吗?

Edw*_*uck 5

你应该看看doA(),doB()doC().如果它们不太可能失败,则在失败时抛出异常.

try {
  doA();
  doB();
  doC();
} catch (FailureException e) {
  // handle failure
}
Run Code Online (Sandbox Code Playgroud)

不合理失败的例子比比皆是,IOException,IllegalParameterException,等.

如果他们有可能失败

if (!doA()) {
  // handle A's failure
  return;
}
if (!doB()) {
  // handle B's failure
  return;
}
if (!doC()) {
  // handle C's failure
  return;
}
Run Code Online (Sandbox Code Playgroud)

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;
Run Code Online (Sandbox Code Playgroud)

相当于

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;
}
Run Code Online (Sandbox Code Playgroud)

这相当于

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;
}
Run Code Online (Sandbox Code Playgroud)

如果"我知道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;
Run Code Online (Sandbox Code Playgroud)