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

这种方法:

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(":)"); } 

根据我的经验,第二种forms更常见,特别是在更复杂的方法中(可能有几个这样的出口点),“扔”和“回”也是如此。 然而,第一种forms可以使得代码的条件结构更加明确。 有没有什么理由相互比较?

(相关: 一个函数是否只有一个返回语句? )

根据我的经验,这取决于代码。 如果我“防守”某些东西,我会这样做:

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

关键是明确的:如果这个陈述是错误的,我不希望这个function继续下去。

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

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

即使它可以写成:

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

这真的是最清楚地显示代码在做什么(不一定哪一位代码是最短的或缩进最less的)。

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

这是一个叫做Guard Clause的模式。 这个想法是做所有的检查,以减less嵌套的条件,以提高可读性。

从链接:

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

你会看到这一切:

 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条件完全相同的方式运行。

很多人认为,一个函数有多个可能的退出点是不好的和/或令人困惑的做法,程序员必须考虑通过他的代码的每一个可能的path。 另一种做法是:

 return (condition) ? var : other_var; 

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

我更喜欢这样写:

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

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

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

  2. 下一个开发者(我自己或其他人)能理解它在做什么,为什么。

  3. 代码在变化方面有多脆弱。

  4. 很简单,因为它需要,而不是更多。 即不超过或在工程中。

一旦我满意以上的快乐,其余的一般就会落到一条线上。

这是宗教的争论,在一天结束的时候,这并不重要。 我甚至会争辩说,在某些情况下,第一种forms更具可读性。 如果你在if-elseif-elseif-else有大量的代码,乍看之下看看默认的返回是多么简单。

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

奥卡姆剃刀原则是“实体不能超越必然性”。

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

但是,在大多数情况下,我希望代码在其意图上尽可能明确。 如果有什么东西可以重构关于你的函数以使其更易于读取,那就去做吧。 作为一名专业的程序员,你的目标应该是为那些在你之后必须维护你的代码(包括2年后你自己)编写程序。 你所能做的任何事情都是值得的。

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

因为它更好。 你也知道你也可以用'{'''来创build几层嵌套,但是没有人真正做到这一点。

其他人可能已经注意到了这一点,但我build议不要在通常情况下使用空值在string预期。 如果你真的想要一个检查来防止有人传递null值,你可以使用断言(在开发时)或unit testing(部署):

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

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

但是这有点偏离主题。 我喜欢把条件放在顶部和守卫条款,如果程序stream程决定它永远不会到达那里,删除elses。

第一种forms简单不复杂 – 当你返回一个值时,你自动离开函数的作用域并返回给调用者,所以之后的任何代码只会在IF语句没有计算为真并随后返回任何东西。

我会争论可读性。 如果您正在扫描代码的屏幕,试图找出代码的function,这是开发人员的视觉提示。

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

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

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

正如你所看到的,不同的人对可读性有不同的看法。 有些人认为较less的代码行会使代码更具可读性。 其他人则认为第二种forms的对称性使其更具可读性。

我的看法可能是,对于持有他们的人来说,两种观点都是正确的。 而推论是你不能编写每个人都能find最佳可读性的代码。 所以,最好的build议就是遵循你所要求的编码标准要做的事情(如果有的话),而且一般会用你的常识。 (如果你背负着一些强硬的笨蛋,坚持他的方式是“正确的”…只是顺其自然。)

因为在eclipse中有一个可选的(默认closures)警告,否则在这种情况下使用;)。

那么,其中一些原因就是惯例,但上面的表格有一个好处。

在编写返回语句时,通常会将最后一个语句设置为默认返回值。 这主要是在重构过程中的帮助 – 否则子句往往会被包装在其他结构中,或者可能意外地被深入到树中。

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

第二种forms如果更简单/更短。 这并不总是意味着更清楚。 我build议你做你发现最清晰的..我个人会写。

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

因为这与编写以下其中一个带来有关程序员意图的证据相同:

 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(":)"); } 

这两种forms是:

  1. 更优雅;
  2. 更容易阅读;
  3. 阅读程序员的学习者和更快捷。
Interesting Posts