为什么在“if x then return”之后很少使用“else”?

时间:2010-07-16 04:06:12

标签: java coding-style if-statement function-exit

此方法:

boolean containsSmiley(String s) {
    if (s == null) {
        return false;
    }
    else {
        return s.contains(":)");
    }
}

可以等同地写成:

boolean containsSmiley(String s) {
    if (s == null) {
        return false;
    }

    return s.contains(":)");
}

根据我的经验,第二种形式更常见,特别是在更复杂的方法中(可能有几个这样的退出点),“throw”和“return”也是如此。然而,第一种形式可以说使代码的条件结构更加明确。是否有理由更喜欢一个而不是另一个?

(相关:Should a function have only one return statement?

23 个答案:

答案 0 :(得分:87)

在这种情况下else将是多余的,并为函数的主代码创建不必要的额外缩进。

答案 1 :(得分:66)

根据我的经验,这取决于代码。如果我'防范'某事,我会做:

if (inputVar.isBad()) {
    return;
}

doThings();

重点很明确:如果该陈述为假,我不希望该函数继续。

另一方面,有一些函数有多个选项,在这种情况下我会这样写:

if (inputVar == thingOne) {
    doFirstThing();
} else if (inputVar == secondThing) {
    doSecondThing();
} else {
    doThirdThing();
}

即使它可以写成:

if (inputVar == thingOne) {
    doFirstThing();
    return;
}
if (inputVar == thingTwo) {
    doSecondThing();
    return;
}
doThingThree();
return;

这真的归结为哪种方式最清楚地显示代码正在做什么(不一定代码的哪一部分最短或压痕最少)。

答案 2 :(得分:32)

这是一种名为Guard Clause的模式。我们的想法是预先进行所有检查,以减少嵌套条件,从而提高可读性。

从链接:

double getPayAmount() {
    double result;
    if (_isDead) {
        result = deadAmount();
    } else {
        if (_isSeparated) {
            result = separatedAmount();
        } else {
            if (_isRetired) {
                result = retiredAmount();
            } else {
                result = normalPayAmount();
            }
        }
    }

    return result;
}

使用Guard子句,您将看到此结果:

double getPayAmount() {
    if (_isDead) return deadAmount();
    if (_isSeparated) return separatedAmount();
    if (_isRetired) return retiredAmount();

    return normalPayAmount();
};

答案 3 :(得分:8)

你会看到这一切:

if (condition) {
    return var;
}
// by nature, when execution reaches this point, condition can only be false,
// therefore, the else is unnecessary
return other_var;

大多数情况下,在这种情况下添加else子句不仅是不必要的,而且很多时候,它会被编译器优化

想想计算机如何看待这个代码(就机器代码而言,为了演示目的简化为伪代码):

0x00: test [condition]
0x01: if result of test was not true, goto [0x04]
0x02: push [var] onto stack
0x03: goto [0x05]
0x04: push [other_var] onto stack
0x05: return from subroutine

代码(再次,这是一个伪代码而不是汇编)对if/then/else条件的行为完全相同。

很多人认为,对于一个函数来说,有多个可能的出口点是不好的和/或混乱的做法,因为程序员必须通过他的代码思考每一条可能的路径。另一种做法如下:

return (condition) ? var : other_var;

这简化了代码,并且不会创建任何新的退出点。

答案 4 :(得分:7)

我更喜欢这样写:

boolean containsSmiley(String s) {
    return s != null && s.contains(":)");
}

答案 5 :(得分:4)

我更喜欢第一种选择,因为它更具人性化。

作为类比,比较接下来的两句话:“如果今天下雨,那就带伞,否则带上太阳镜。”并且“如果今天下雨,那就带伞,带上太阳镜”。第一个句子对应于问题的第一个代码块,第二个句子对应于第二个。第一个更清晰可读,不是吗?

答案 6 :(得分:4)

与任何关于编码风格的“讨论”一样,没有正确的答案。我更愿意应用这些考虑因素:

  1. 代码是否在所有情况下都按预期工作。 (最少惊讶的原则)

  2. 下一位开发人员(我本人或其他人)可以了解它的作用和原因。

  3. 关于变更的代码有多么脆弱。

  4. 很简单,因为它需要而且不再存在。即没有超过或低于工程。

  5. 一旦我很高兴我对上述事情感到满意,其余的一般都会落到一线。

答案 7 :(得分:3)

其他人可能已经注意到了这一点,但我建议不要在通常需要字符串的地方使用空值。如果您确实需要检查以防止有人传递空值,您可以使用断言(在开发时)或单元测试(部署):

boolean containsSmiley(String s) {
    assert s != null : "Quit passing null values, you moron.";
    return s.contains(":)");
}

我已经改为一般的经验法则:从不。永远。传递空值,除非外部API调用明确要求它。第二:如果外部方法可能返回空值,请将其替换为合理的非空值(例如空字符串)或添加一个整齐的检查。我厌倦了重复的if (thing == null)检查。

但这有点偏僻。我喜欢把短条件放在顶部和保护条款上,如果程序流程规定它永远不会到达那里,那么就删除它们。

答案 8 :(得分:2)

if语句正在检查/强制执行您未收到空值的合同/期望。出于这个原因,我宁愿把它与函数的其余部分分开,因为它与你想要完成的事情的实际逻辑没有任何关系(虽然这种情况非常简单)。

但在大多数情况下,我更喜欢代码在其意图中尽可能明确。如果您可以对某些功能进行重组以使其对其他人更具可读性,那就去做吧。作为一名专业程序员,您的目标应该是为那些必须在您之后维护代码的人(包括2年后的自己......)进行编程。你能做些什么来帮助他们是值得的。

答案 9 :(得分:2)

因为它更好。你知道你也可以使用'{''}'来创建几个级别的嵌套,但是没有人真正做到这一点。

答案 10 :(得分:2)

Occam's Razor的原则是“实体不得超越必要性。”

答案 11 :(得分:2)

这是宗教争论,在一天结束时并不重要。我甚至认为第一种形式在某些情况下更具可读性。如果您在if-elseif-elseif-else中有大量代码,乍看之下就更容易看到默认返回值。

if (s == null) {
    return false;
}
else if (s.Contains(":))")) {
    return true;
}
else if (s.Contains(":-(")) {
    return false;
}

return s.contains(":)");

答案 12 :(得分:2)

else是多余的。此外,一些IDE(Eclipse)和分析工具(可能是FindBugs)可能会将其标记为警告或错误,因此在这种情况下,程序员可能会将其删除。

答案 13 :(得分:0)

如您所见,不同的人对可读性有不同的看法。有些人认为较少的代码行会使代码更具可读性。其他人则认为第二种形式的对称性使其更具可读性。

我的看法可能是,两种观点都是正确的......对于持有它们的人来说。结果是你不能编写每个人都发现最佳可读性的代码。因此,最好的建议是遵循您的强制编码标准所要做的事情(如果它对此有所说明)并且通常使用您的常识。 (如果你背负着一些强烈的吵闹声,坚持认为他的方式是“正确的”......只需顺其自然。)

答案 14 :(得分:0)

虽然有一个else是正确的,并且在逻辑和运行性方面没有任何问题,但是当函数在if / else范围之外没有return语句时,我喜欢避免最初的WTF时刻。

答案 15 :(得分:0)

因为在这种情况下使用了else,所以在eclipse中有一个可选的(默认关闭)警告;)。

答案 16 :(得分:0)

嗯,有些原因只是惯例,但上面的表格有一个优点......

在编写return语句时,通常会将最后一个语句设为默认返回值。这主要有助于重构 - 否则子句往往会被包裹在其他结构中,或者可能会意外地被移动到树中更深处。

答案 17 :(得分:0)

从维护角度来看,我更喜欢一个退出点。最终结果可以在一个出口点而不是n个出口点进行修改(或修饰)。

答案 18 :(得分:0)

第二种形式,如果更简单/更短。这并不总是意味着更清楚。我建议你做你觉得最清楚的事。我个人会写。

static boolean containsSmiley(String s) { 
    return s != null && s.contains(":)"); 
} 

答案 19 :(得分:0)

在我看来,第二个更有意义。它更像是一个“默认”动作,就像一个开关。如果它与任何其他退出点都不匹配,那么就这样做。那里你真的不需要别的东西。我会说如果整个函数只是if和elseif,那么其他就有意义,因为它是一个巨大的条件。如果有多个条件和其他函数在其中运行,那么将使用最后的默认返回。

答案 20 :(得分:0)

因为它与编写以下内容之一相同,它带来了程序员意图的证据:

boolean containsSmiley(String s) {
    if (s == null)   // The curly braces are not even necessary as the if contains only one instruction.
        return false;

    return s.contains(":)");
}

甚至这个:

boolean constainsSMiley(String s) {
    return string.IsNullOrEmpty(s) ? false : s.Contains(":)");
}

这两种形式是:

  1. 更优雅;
  2. 易于阅读;
  3. 阅读程序员更精简,更快捷。

答案 21 :(得分:0)

我认为可读性。如果您正在扫描代码屏幕以试图弄清楚代码的作用,那么这对开发人员来说是一个视觉提示。

...但它并不是真的需要,因为我们都很好地评论我们的代码,对吧? :)

答案 22 :(得分:0)

第一种形式只是不那么冗长 - 当你返回一个值时,你自动离开你所在函数的范围并返回给调用者,因此其后的任何代码只有在IF语句不能执行时才会执行评估为真,然后返回任何内容。