这是滥用try / finally吗?

时间:2010-02-09 16:45:10

标签: java language-agnostic coding-style

鉴于多个返回语句是可以接受的(我有点不同意,但是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中进行讨论。

11 个答案:

答案 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块(例如从文件读取,读取intString)。因此,在方法的整个代码上放置一个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来呈现一个版本(*邪恶的笑容*。)