鉴于多个返回语句是可以接受的(我有点不同意,但是let us digress),我正在寻找一种更可接受的方式来实现以下行为:
选项A :多次返回,重复代码块
public bool myMethod() {
/* ... code ... */
if(thisCondition) {
/* ... code that must run at end of method ... */
return false;
}
/* ... more code ... */
if(thatCondition) {
/* ... the SAME code that must run at end of method ... */
return false;
}
/* ... even more code ... */
/* ... the SAME CODE AGAIN that must run at end of method ... */
return lastCondition;
}
每次方法返回时,看到相同(小)代码块重复三次会让我觉得很脏。此外,我想澄清一下,上面的两个return false
陈述当然可以被描述为返回中间方法......它们绝对不是“守卫陈述”。
选项B 稍微更容易被接受吗?我觉得我可能会滥用try / finally,我希望有一些完全不同的东西我应该做什么。
选项B :多次返回,尝试/最后阻止(没有捕获阻止/异常)
public bool myMethod() {
try {
/* ... code ... */
if(thisCondition) {
return false;
}
/* ... more code ... */
if(thatCondition) {
return false;
}
/* ... even more code ... */
return lastCondition;
} finally {
/* ... code that must run at end of method ... */
}
}
最后,选项C是 my 一书中的最佳解决方案,但我的团队不管出于何种原因都不喜欢这种方法,因此我正在寻求妥协。
选项C :单一返回,条件块
public bool myMethod() {
/* ... code ... */
if(!thisCondition) {
/* ... more code ... */
}
if(!thisCondition && !thatCondition) {
/* ... even more code ... */
}
/* ... code that must run at end of method ... */
return summaryCondition;
}
如果您想讨论多个退货声明,请在this question中进行讨论。
答案 0 :(得分:29)
如果代码需要运行,即使其他代码抛出异常,那么finally
块也是正确的解决方案。
如果在异常的情况下不需要运行(即只需要“正常”返回),那么使用finally
将滥用该功能。
就个人而言,我会以单回归方式重写该方法。不是因为我虔诚地赞同这个想法(我没有),而是因为它最适合这种方法结束的代码。
当该代码变得过于复杂时(这是一种非常现实的可能性),那么是时候通过提取一个或多个方法来重构该方法。
最简单的重构就是这样:
public boolean myMethod() {
boolean result = myExtractedMethod();
/* ... code that must run at end of method ... */
return result;
}
protected boolean myExtractedMethod() {
/* ... code ... */
if(thisCondition) {
return false;
}
/* ... more code ... */
if(thatCondition) {
return false;
}
/* ... even more code ... */
return lastCondition;
}
答案 1 :(得分:28)
例外情况应该是例外的,所以我不喜欢选项B,如果周围没有其他例外(注意事项为downvoters - 我没有说最终是不正确的,只是因为如果没有例外我不想拥有它 - 如果您有理由请评论)
如果总是需要代码,那么如何重构为2个函数
public bool myMethod() {
bool summaryCondition = myMethodWork();
// do common code
return summaryCondition;
}
private bool myMethodWork() {
/* ... code ... */
if(thisCondition) {
return false;
}
/* ... more code ... */
if(thatCondition) {
return false;
}
/* ... even more code ... */
return lastCondition;
}
答案 2 :(得分:15)
这是GOTO
*鸭*
答案 3 :(得分:3)
如果代码需要在Exception
时运行,那么finally
不仅是一个不错的选择,它也是必须的。如果不是这种情况,则不需要finally
。看起来你想要找到“看起来”最好的格式。但这里没有什么利害关系。
答案 4 :(得分:3)
您的选项C 解决方案与最佳解决方案相距甚远,因为它可以充分编码您正在尝试完成的正确执行顺序。
同样,使用嵌套的if语句也可以做同样的事情。它可能在视觉上不那么吸引人,但它更容易理解,并使执行流程非常明显:
public bool myMethod() {
boolean rc = lastCondition;
/* ... code-1 ... */
if (thisCondition) {
rc = false;
}
else {
/* ... code-2 ... */
if (thatCondition) {
rc = false;
}
else {
/* ... code-3 ... */
rc = ???;
}
}
/* ... the code that must run at end of method ... */
return rc;
}
简化代码产量:
public bool myMethod() {
boolean rc = false;
/* ... code-1 ... */
if (!thisCondition) {
/* ... code-2 ... */
if (!thatCondition) {
/* ... code-3 ... */
rc = lastCondition;
}
}
/* ... the code that must run at end of method ... */
return rc;
}
简化代码还揭示了您实际尝试实现的目标:您正在使用测试条件避免执行代码,因此当条件为时,您应该执行该代码假而不是在 true 时做某事。
要回答有关 try-finally 阻止的问题:是的,您可以滥用它们。你的例子不够复杂,无法保证try-finally的使用。但是,如果它更复杂,它可能会。
请参阅我的文章:Go To Statement Considered Harmful: A Retrospective, "Exception Handling"。
答案 5 :(得分:2)
如何更多地分解更多东西(在很长一段时间内没有使用Java的逻辑运算符),如下所示:
public bool findFirstCondition()
{
// do some stuff giving the return value of the original "thisCondition".
}
public bool findSecondCondition()
{
// do some stuff giving the return value of the original "thatCondition".
}
public bool findLastCondition()
{
// do some stuff giving the return value of the original "lastCondition".
}
private void cleanUp()
{
// perform common cleanup tasks.
}
public bool myMethod()
{
bool returnval = true;
returnval = returnval && findFirstCondition();
returnval = returnval && findSecondCondition();
returnval = returnval && findLastCondition();
cleanUp();
return returnval;
}
答案 6 :(得分:2)
除非你需要打破内部循环,否则不要滥用try / finally。虐待/同时。
bool result = false;
do {
// Code
if (condition1) break;
// Code
if (condition2) break;
// . . .
result = lastCondition
} while (false);
答案 7 :(得分:0)
使用try / finally控制流程对我来说就像使用GOTO一样。
答案 8 :(得分:0)
是否有理由不能简单地存储返回值,并且不属于if?
bool retVal = true;
if (retVal && thisCondition) {
}
/* more code */
if ( retVal ) {
/* ... code that must run at end of method, maybe inside an if or maybe not... */
}
return retVal;
答案 9 :(得分:0)
IMO的想法是在可以引发已知异常的一小部分代码(例如方法调用)上放置try
块(例如从文件读取,读取int
到String
)。因此,在方法的整个代码上放置一个try
块实际上是不可取的,除非您实际上期望每个if
条件代码可能抛出相同的异常集。我只是为了使用try
而没有看到使用finally
块的意义。
如果我没有弄错的话,在try
中放入大块代码也会让它慢得多,但不确定在最新版本的Java中是否属实。
就个人而言,我会选择选项C.但我也没有任何反对选项A.
答案 10 :(得分:0)
除非必须在方法结尾处运行的代码使用方法局部变量,否则可以将其提取为如下方法:
public boolean myMethod() {
/* ... code ... */
if(thisCondition) {
return myMethodCleanup(false);
}
/* ... more code ... */
if(thatCondition) {
return myMethodCleanup(false);
}
/* ... even more code ... */
return myMethodCleanup(lastCondition);
}
private boolean myMethodCleanup(boolean result) {
/* ... the CODE that must run at end of method ... */
return result;
}
这仍然看起来不太好,但它比使用类似goto的结构更好。为了说服你的队友,1回归的解决方案可能不那么糟糕,你也可以使用2 do { ... } while (false);
和break
来呈现一个版本(*邪恶的笑容*。)