代码之家  ›  专栏  ›  技术社区  ›  Dolph

这是一种尝试/最终的滥用吗?

  •  31
  • Dolph  · 技术社区  · 15 年前

    鉴于 可接受多个返回语句 (我有点不同意,但是 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 上面的语句当然可以描述为返回mid方法…他们绝对不是“守卫声明”。

    选项B 轻微地 更容易接受?我觉得我可能会滥用尝试/最后,我希望有完全不同的东西,我 应该 正在做。

    选项B :多次返回, 尝试/最终 块(没有catch块/异常)

    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是 我的 可以,但是我的团队不喜欢这种方法,无论出于什么原因,因此我正在寻找一种折衷的方法。

    选项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 回复  |  直到 13 年前
        1
  •  28
  •   mmmmmm    13 年前

    例外情况应该是例外的,所以如果周围没有其他例外情况,我不喜欢选项B(请注意,对于投反对票的人-我不说最终的结果是错误的,只是如果没有例外情况,我更不喜欢这样做-如果你有理由,请评论)

    如果总是需要代码,那么重构为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
  •  29
  •   Joachim Sauer    15 年前

    如果代码需要运行,即使任何其他代码引发异常,则 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;
    }
    
        3
  •  15
  •   David Oneill    15 年前

    这是一个完美的地方 GOTO

    *鸭子*

        4
  •  3
  •   David R Tribble    15 年前

    你的 选项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;  
    }
    

    简化的代码还揭示了您实际上试图实现的目标:您使用测试条件 避免 因此,当条件为 错误 而不是在他们 .

    回答你关于 最后尝试 布洛克:是的,你可以虐待他们。您的示例不够复杂,不足以保证最终使用Try。不过,如果更复杂的话,可能会。

    请看我的看法: Go To Statement Considered Harmful: A Retrospective , "Exception Handling" .

        5
  •  3
  •   L. Cornelius Dol    15 年前

    如果代码需要运行,即使存在 Exception 然后 finally 这不仅是一个好的选择,也是必须的。如果不是这样的话, 最后 不需要。看起来您想找到“看起来”最好的格式。但这里几乎没有什么危险。

        6
  •  2
  •   glenatron    15 年前

    如何把它稍微多一点来给出更多的东西(原谅我没有使用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; 
    }
    
        7
  •  2
  •   Rex Kerr    15 年前

    不要滥用尝试/最终,除非你需要打破内部循环。虐待行为。

    bool result = false;
    do {
      // Code
      if (condition1) break;
      // Code
      if (condition2) break;
      // . . .
      result = lastCondition
    } while (false);
    
        8
  •  0
  •   cherouvim    15 年前

    使用Try/Finally控制流程对我来说就像使用Goto。

        9
  •  0
  •   chris    15 年前

    有没有理由不能简单地存储返回值,然后从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;
    
        10
  •  0
  •   MAK    15 年前

    我的想法是 try 在代码的一小部分(例如方法调用)上阻塞,该代码可以引发已知的异常(例如从文件中读取、读取 int 到A String )。所以放一个 尝试 一个方法的整个代码上的块实际上不是一种方法,除非您实际期望每个 if 条件代码可能引发相同的异常集。我看不出使用 尝试 为了使用 finally .

    如果我没有弄错,在 尝试 也使它慢很多,但不确定在Java的最新版本中是否如此。

    就我个人而言,我会选择C。但我也没有任何反对A的选择。

        11
  •  0
  •   rsp    15 年前

    除非必须在方法末尾运行的代码使用方法局部变量,否则可以将其提取到如下方法中:

    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 S(邪恶的笑容)

    推荐文章