只要一个返回语句

别再这样写了:

public boolean foo() {
 if (true) {
   return true;  
 }  else {  
 return false;  
 }
}

每次当我深入某个开源项目,看到大概是某个专家写的、并被有经验的专业人士审查过的这样的代码,我都会惊讶不已,竟然没有人去阻止这个开发者在这个方法里胡乱的放置返回语句。

请告诉我,把代码写成下面的样子很难吗?

public boolean foo() {  
 boolean flag = true;  
 if (true) { 
   flag=true;
 }  
 else {
   flag=false;
 }
 return flag;
}

这是Java基本常识。实际上,这不仅是Java基本常识,这是小学水平的Java知识。如果你的方法返回一个值,你应该在方法的开始处把它声明做一个变量。然后再去做一些赋予这个变量正确意义的操作。然后,在你的最后一行,把这个变量返回给调用程序。这样做不仅仅是为写出好的代码,这是一种有教养的表现。

你是否曾试图修改过一些在方法里到处都是返回语句的程序代码?无从下手。事实上,去维护这样的代码,你第一要做的是重新组织它的结构,让它里面不再有一大堆的返回语句。这样才能把事情做好。没有任何一个方法是不可以写成只在末尾处有一个的、单一的、易于找到的返回语句的形式的。

的确,烂程序员总有一万个理由来说明他们为什么编写出这样糟糕的程序代码。“我只是为了避免在返回时一堆的多余的条件判断语句。”那好,首先,我告诉你,计算机中执行一些条件判断语句时是该死的快,你用短路一个方法来节省CPU的一两个指令操作不是显的太荒诞了吗。此外,如果这些所谓多余的条件判断语句最终没有派上用场的话,这是否是一个有用的信号来说明你的“多余”的代码可能需要重写,也许可以把它们重构成另外一个方法,让它们显的不多余?

关键要说的是,没有任何理由可以为写糟糕的代码或当懒惰的程序员做托辞,特别是当写出好的代码并不是那么困难的情况下。不要在写出里面有成百上千个返回语句的方法了。Java里的方法只可以返回一个值,相应的,一个方法应该有且只有一个返回语句。

[英文原文:A return to Good Code ]

分享这篇文章:

75 Responses to 只要一个返回语句

  1. halida says:

    这个应该是搞笑吧…

  2. 徐风子 says:

    真没看懂他想说啥。

  3. zoujia says:

    貌似有点道理\(^o^)/~

  4. pip says:

    很有道理,但是真实编程中,懒得这么做,小点的函数还好,大一点的话就很麻烦了、、、

  5. Lyd says:

    完全不赞同这样的观点,举个例子,难道我在一个多重嵌套的for循环里面,要专门每次判断是否满足退出条件,然后进行多次break;或者其他什么判断操作,而不是直接return -1;来得方便?
    显然这是具体情况具体分析的吧?固然不能有太多return,但有时候有两三个return还是必要的。

    • zflinux says:

      我也这么认为
      我是搞php的。

    • Yonghang Jiang says:

      如果真有多重循环,或许的确能用一个return,前提是那个多重循环被放到一个单一的函数中,换言之那个函数的内容就只有多重循环,没别的。

      另外,用一个goto也能很好的完成从多重循环里一次跳出的功能。只要goto总是往下跳,就不会有任何问题。

      我还用过一个叫做stop_flag的变量让所有循环都检测它。

      其实需要多重循环的地方要一次就跳出是很奇怪的需求。

  6. sjinny says:

    受不了了。。。如果是if(a==b) return true; else return false;这样的代码,那当然应该写成return a==b;。但是文中的情况则和作者的说法恰恰相反,作者推荐的做法利用了那个缓存返回值变量的side effect,这也留下了一个缺陷:看代码的人如果不把函数里所有代码检查一遍,就无法确认在某次赋值之后是否它还会再被人改变,反过来,维护中很容易把代码越改越乱,而且这样的写法会使函数中的嵌套层次更深。看来我不得不对java程序员抱有偏见了。

  7. Nickel says:

    这篇文章的观点太片面了。我也是认为固然不应该return满天飞,但不能为了单这一个理由而只限制用一个return,非常不实用的意见。

  8. zen says:

    赞同这个观点:
    如果该函数不是返回boolean,返回int。在内部的处理比这个要复杂的情况下,问你怎么出Trace,说明这个函数返回时返回什么值,是不是在每个if-else中都要添加出Trace的代码。如果这么写你在改代码添加出Trace的代码时是很方便的。

    如果在第一个if-else后还要进行其他的处理啊,在这种方式的代码是很方便修改的。所以说代码是为了维护而写的,不是为了实现功能才这么写的。

  9. SevenLeaf says:

    大一点的函数配合goto就行了
    每次进入时都应该先定义一个retStaus之类的东西。
    可以参考一下windows的内核代码

  10. bookjohn says:

    The author has not ever read books from Martin Fowler, Kent Beck or Steve Mcconnell.

  11. mayday says:

    不敢苟同文章观点,作者是不是没写过多个if-else的语句吗?
    本人曾经被文章的模式折腾过,深深地感受到其中的弊端,以致后来全部用多个return来返回,这也是本人曾经所鄙视的。
    先抛开效率不说,如果是多个if-else,需要用一个变量来保存变量,不管是阅读还是调试,工作量都是巨大的,因为你真不明确地知道,到底返回的是哪种情况。

  12. alloy says:

    作者说的很对,只需要一个return,一个入口,一个出口

  13. ahhuiyang says:

    赞同!如果函数大一点,这种写法很有必要,在我的代码中基本都是这样写的。

  14. iosnew says:

    有道理。
    不过在多个if–else–时,就很痛苦了。对DEBUG和维护都是一种不易的事情。

  15. 亮子 says:

    我不明白!
    如果只在最后一行Return,就意味着不管什么情况下,这个函数都要从头执行到尾,这样合理吗?早点返回有什么不好!

  16. 陈绪 says:

    扇入扇出的问题吧

  17. Levi says:

    xcode中若是用第一种写法,则会产生一个警告,消除警告的办法就是用第二种写法.

  18. shily says:

    看了评论,大概都不太赞成文中的观点,我认为:
    1,你们的循环太复杂了
    2,你们的函数太长了。

  19. 明日黄菜 says:

    看了上面这么多的评论,
    我赞同作者的观点,我真的赞同,
    一个方法,仅仅是一个方法,我相信这一个方法只为了一个或者某一类功能的实现而去写的,这样一来,这个方法的代码长度不会很长的,所以,一个return语句足够了,如果你非要让这么一个方法去实现一大堆功能而把这个方法的长度到达几千行的话,那么我也没办法!如果真的要这样写的话,那我也劝告,你把这么长的方法分开多个方法会很难吗?这么长的方法分开多个方法,易读性和维护不是更加好吗?
    暂且我支持一个方法只需一个return语句!

  20. jimmy says:

    作者想表达的应该是方法(函数)只有一个出口的观念 我觉得这观念挺好的 基本上我一直这么做

  21. 泥菩萨 says:

    其实,在你的语言中合适怎么用就怎么用。人是活的。不一定要遵守某个规条。就算这篇文章的原文作者是Bill Gates 。也没必要去守它。
    如果程序开发上有规条可寻。那么早就用机器批量开发了。何须要人!
    我不可否认一个返回的好处。有时候能简化理解。但有时候函数逻辑太多。提前返回的话。反而能简化理解。实际上我在写程序的时候。两种方法都在用。其主要目的是为了:让别人能更容易看得懂我的代码。

  22. wesley says:

    我是有这方面的感受的,程序不容易出错,逻辑清晰!

  23. wingfire says:

    这是C风格吧。C++中早就鼓励多个返回路径了。
    关键是那种方式对读代码有利,就用哪种。

  24. cheery says:

    仁者见仁智者见智 看了各位大侠们的评论 受用 !顶一个
    支持泥菩萨所说:”我不可否认一个返回的好处。有时候能简化理解。但有时候函数逻辑太多。提前返回的话。反而能简化理解。实际上我在写程序的时候。两种方法都在用。其主要目的是为了:让别人能更容易看得懂我的代码”

  25. hyp says:

    作者的观点在大部分情况下适用,也是一种良好的编程习惯。
    不过,也不能被这种观点所束缚了,比如在一个判断素数的方法里,这么写可能更好:
    bool isPrime(int n) {
    if(n < 2)return false;
    if(n == 2)return true;
    if(n%2 == 0)return false;
    for(int i=3; i<=sqrt(n); i+=2){
        if(n%i == 0)return false;
      }
    return true;
    }

    • wene says:

      按作者的思路也可以这么写:
      bool isPrime(int n) {
      bool flag = true;
      if(n < 2)
      flag = flase;
      else if(n == 2)
      flag = true;
      else if(n%2 == 0)
      flag = false;
      else
      {
      for(int i=3; i<=sqrt(n); i+=2){
          if(n%i == 0) {flag = false;break;}
        }
      }
      return flag;
      }

      其实每个人都有自己写代码的风格,让人容易理解的写法肯定不止一种,而且又和程序员周围的环境有关,比如在香港大多数人是说粤语的,你去说普通话反倒有很多本地人听不懂了。感觉作者像是一个气急败坏的偏执主义者,还是处女座的

  26. champ says:

    这个例子可以看到java程序员乐于用条条框框约束自己,而评论中明显反映出用C/C++的人善于发散思维、合理的打破规矩。
    于是,后来google也意识到了原生java程序员思维上面的不足,于是在Android平台上开放了NDK。

  27. ljf10000 says:

    过度使用并频繁修改变量才是bug之源。

    java我不懂,换成C演示一下
    #define boolean int
    #define true (1,assert(LINE))
    #define false (0,assert(LINE))

    boolean foo() {
    if (true) {
    return true;
    } else {
    return false;
    }
    }

    那么在返回点直接返回值,能够得到返回点的行号。而你的方式不行。

  28. kongkong says:

    完全不赞同这种形式化的约束。一句话,如果事实真的向作者说的那样,高级语言中就不会有return关键字了,我们会在函数的最后一行写上一个变量作为返回值,实在荒唐。

  29. TonySeek says:

    教条主义……到头来也没说清楚写多个 return 哪里“糟糕”,只写一个有哪些好处,不过是满足自己的强迫症罢了。这种很个人的东西拿来约束自己没什么,拿来约束别人就过分了。PS:@kongkong 说的很有道理

  30. belial says:

    我一般是这样写的
    public boolean foo() {
    if (true) {
    return true;
    }
    return false;

    }

  31. camelwoo says:

    如果是这种结构,我也倾向于最后有一个 return,但有时候不行。

  32. peach5460 says:

    其实我更倾向于早点返回

  33. lys says:

    在一个短函数里,有多少个返回语句其实无所谓。因为一目了然。函数长了只有一个返回语句的话也不见得就容易理解。所以尽量把函数写短点吧,不要纠结一个函数有几个出口的问题了。

  34. w1e3 says:

    首先,第一个代码示例确实不对,
    但我给出的修正和第二个示例也不相同。
    public boolean foo()
    {
    if (true)
    return true;
    return false;
    }
    如此简单的3行代码。

    对于第二个示例,只是能达到目的的另一种写法,
    但很明显,这个写法也有相当的问题。以下是正确的写法

    public boolean foo()
    {
    boolean flag = false;
    if (true)
    flag = true;
    return flag;
    }

    4 行代码。技术上来讲,很难说哪种写法更好,完全是个人偏好。
    但有些情况比较适合第一种写法。像示例中那样简单的情况,第一种方式就很好,
    还有一种就是可能几个条件判断不属于同一类型,比如

    if ((p = malloc(sizeof(int))) == NULL)
    return -1;
    if ((fp = fopen(“hello”, “rb”)) == NULL)
    return -1;
    也有些代码比较适合第二种写法,比较经典的是资源申请和释放,如

    if ((fp = fopen(“hello”, “rb”)) != NULL) {
    retValue = fgetc(fp);
    fclose(fp);
    }

    return retValue;

    还有就是多线程需要加锁访问的数据

    if (!check(“hello”)) {
    LOCK;
    flag = insert(“hello”);
    UNLOCK;
    }
    return flag;

  35. 北风 says:

    作者显示太骄傲了,反对这种不说任何理由就直接说应该怎么怎么做而且还要加一句“写成XXX这样很难吗?”。
    所谓“在函数开始声明一个变量,中间赋值,最后返回”这种方式到底有什么好处?请明确说明。我个人觉得这只是作者的习惯而已,未必是最好的。

  36. Ares says:

    具有太多的return语句的函数,让人看起来很头疼,尤其是当一个函数很长的时候,你都不知道该函数到底要干什么,到处是return,也很难让人理解。
    一个方法一个出口,顶!

  37. simebian says:

    完全赞同作者的,本事是开发超过7年了

  38. poet says:

    都别争了,这个代码的最佳写法应该是:

    public boolean foo() {
    return (true);
    }

    每次看到 if (true) return true; else return false; 就感到隐隐的蛋疼,难道 true 本身不是一个表达式吗?让这个表达式直接用 return 返回很难吗?

  39. froest says:

    这个感觉有点扯= =!

  40. FF says:

    跟作者的想法正好相反,作为一个老程序员,并且带领过多个超二十万行代码的项目,我明确的把在满足条件时直接return写进了我项目的代码规范文档,严禁作都所推荐的那种写法。

    因为总体上这样可以更容易的让别人看明白程序的意图,节省阅读及调试时间。

  41. 凝霜 says:

    无非就是一个单一出口原则么……自己喜欢就去做,不喜欢也无所谓。你要是真关心软件质量,那你的函数就不应该大于30行,现代编辑器都能在一屏内显示的下,根本不会造成理解上问题。

  42. ErenNo1 says:

    忽然想起一个问题:
    if(XXOO)
    {
    return true;
    }
    else{
    return false;
    }


    if(XXOO)
    {
    return true;
    }
    return false;
    什么区别?

  43. LYF says:

    没区别,两个写法都很烂。哥,你就不能写成return XXOO吗?

  44. kindle says:

    那些以教养,修养等等之类的理由优化代码的guy,都t妈是个娘娘腔,死脑筋,其实称不上是优化代码,完全是在强j别人的思维,国内外不缺这种博文写的比代码多的娘娘腔

  45. lizeqiangd says:

    作为一个高中生,我认为下面的写法蠢得不能再蠢,是一种低能幼稚儿童想证明自己比别人厉害的一种幼稚表现。在java这种不管垃圾回收的代码中,这样写也许没分别,在其他代码中会导致产生无法回收的垃圾,还会影响代码的执行效率,这种低能的表现更凸显出java语言的良好和开发者水平低下的问题。

  46. jess says:

    没滥用goto已经很对得起你大爷了

  47. llddy says:

    public boolean foo() {
    return 1==1 ? true:false;
    }

    你有代码洁癖吧

  48. CHerylChen says:

    I love the return ! and it is always a MUST and SHOULD !

  49. 金鑫  这篇文章
  50. shady 对这篇文章的反应是笑死了
  51. whj 对这篇文章的反应是垃圾
  52. richard 对这篇文章的反应是笑死了
  53. 吴金刚 says:

    判断语句是该死的快,但如果决断的内部实现相当慢的,是不是效率就降低了呢

  54. Leon Li says:

    如果你这么强烈地反对多个出口,干脆把C的return关键字取消算了;这么害怕指针,取消算了;这么害怕数组下标越界,编译器一律自动加上边界检查代码。。。。这不基本上就是BASIC了吗,你MISRA直接规定汽车电子开发一律用BASIC得了,针对C搞那么多规则干鸟啊

  55. Leon Li says:

    MISRA给了我一辆超级豪华跑车,并且规定:
    1. 速度不可以超过 15km/h
    2. 所以车窗包括全景天窗必须打开,下雨也不例外
    3. 上坡是不许踩油门,只能下车推
    4. 下坡是不许踩刹车,只能下车拽

    你TM给我辆自行车不就得了吗?干嘛这么整人呢!

  56. Leon Li says:

    MISRA给了我一辆超级豪华跑车,并且规定:
    1. 速度不可以超过15km/h
    2. 所有车窗包括全景天窗必须打开,下雨也不例外
    3. 上坡不许踩油门,只能下车推
    4. 下坡不许踩刹车,只能下车拽
    你TM给我辆自行车不就的了,干嘛这么整人啊?

  57. mac says:

    作者不懂什么叫代码可读性。认同的人需要多做些项目进步一下。

  58. jianwu says:

    这个单一出口的原则,是传统计算机语言教科书中对初学者,最害人的一条定理。我竟然还看的不少所谓有经验的程序员还在坚守这个原则。稍有编程经验,而且善于思考的程序员应该明白如何让你的程序更可读,而不是拘泥于一些毫无意义的原则。

  59. jianwu 对这篇文章的反应是笑死了垃圾
  60. Jassor 对这篇文章的反应是垃圾

发表评论

电子邮件地址不会被公开。 必填项已用*标注