Java 这是对try/finally的滥用吗?

Java 这是对try/finally的滥用吗?,java,language-agnostic,coding-style,Java,Language Agnostic,Coding Style,鉴于多个返回语句是可以接受的(我有点不同意,但是),我正在寻找一种更可接受的方法来实现以下行为: 选项A:多次返回,重复代码块 public bool myMethod() { /* ... code ... */ if(thisCondition) { /* ... code that must run at end of method ... */ return false; } /* ... more code ... *

鉴于多个返回语句是可以接受的(我有点不同意,但是),我正在寻找一种更可接受的方法来实现以下行为:

选项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
语句肯定可以描述为return mid method。。。绝对不是"防卫声明"

方案B是否稍微可以接受?我觉得我可能会滥用try/finally,我希望我应该做一些完全不同的事情

选项B:多次返回,尝试/最终块(无捕获块/异常)

最后,在我的书中,选项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;
}

如果您想讨论多个返回语句,请在中进行讨论。

如果即使在任何其他代码引发异常时代码也需要运行,那么
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;
}
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; 
}

例外情况应该是例外情况,因此如果没有其他例外情况,我不喜欢选项B(请注意,对于反对者,我并不是说“最终拥有”是不正确的,只是如果没有例外情况,我宁愿不拥有它-如果你有理由,请评论)

如果总是需要代码,那么重构成两个函数如何

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;
}

使用try/finally来控制流对我来说就像使用GOTO一样。

有什么原因不能简单地存储返回值,而不使用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;

我的想法是在一小部分代码(例如方法调用)上放置一个
try
块,该代码可以引发已知的异常(例如从文件读取,将
int
读取到
字符串
)。因此,在方法的整个代码上放置一个
try
块并不是一个好办法,除非您实际上期望每个
if
条件代码都可能抛出相同的异常集。我不认为仅仅为了最后使用
而使用
try
块有什么意义

如果我没有弄错的话,将大块代码放在
try
中也会使速度慢很多,但不确定这在最新版本的Java中是否正确


就我个人而言,我会选择C选项。但我也不反对A选项。

这是一个进行
GOTO


*鸭子*

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

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-return解决方案可能没有那么糟糕,您还可以使用2
do{…}while(false)来呈现一个版本
break
的(*邪恶的咧嘴笑*)

把它再拆分一下,这样做怎么样(原谅我很久没有使用Java的逻辑运算符):

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;
}
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; 
}

如果代码需要运行,即使出现
异常
,那么
最终
不仅是一个好选择,而且是必须的。如果不是这样的话,
最后
是不必要的。看起来您希望找到“看起来”最好的格式。但是这里没有更多的利害关系。

不要滥用try/finally,除非你需要打破内部循环。滥用职权

bool result = false;
do {
  // Code
  if (condition1) break;
  // Code
  if (condition2) break;
  // . . .
  result = lastCondition
} while (false);

您的选项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;  
}
简化后的代码还揭示了您实际试图实现的目标:您使用测试条件来避免执行代码,因此您可能应该在条件为false时执行该代码,而不是在条件为true时执行某些操作

要回答您关于的问题,请尝试最后使用块:是的,您可以滥用它们。您的示例不够复杂,无法保证使用try finally。不过,如果它更复杂,它可能会更复杂


请参见我的观点:。

那么我该怎么办?这里也没有例外。如果你没有提供选项C,我会用选项C回答!你的队友对选项C有什么反对意见?如果“必须在方法末尾运行的代码”需要更改,他们的答案是什么?我同意Donal的观点。我喜欢选项C。他们的具体反对意见是什么?我真的不想为他们说话,但据我理解,他们不喜欢选项C只是因为它没有多个返回语句。我不确定这是否是一个合理的立场,但这是另一个话题
我建议从
save(…)
抛出一个异常,以迫使人们处理这个案例,而不是忽略它(或忘记它!)。如果是