在循环中使用return还是在循环外使用?

46

今天,有人指出我在Java中错误使用了return关键字。我写了一个简单的for循环来验证某个东西是否在一个数组中。假设array是长度为n的数组,这是我的代码:

for (int i = 0; i < array.length; ++i) {
    if (array[i] == valueToFind) {
        return true;
    }
}
return false;

现在有人告诉我,这不是很好的编程方式,因为我在循环内使用了 return 语句,这会导致垃圾回收失效。因此,更好的代码应该是:

int i = 0;
while (i < array.length && array[i] != valueToFind) {
    ++i;
}
return i != array.length;

问题是我无法给出为什么第一个for循环不是一个好的实践方法的合适解释。有人可以给我一个说明吗?


那个人到底为什么认为第一个不好?会影响垃圾回收吗? - Poindexter
12
如果GC出现故障,那是JVM的问题,而不是您的程序的问题... 您的代码完全有效。 - Alexander Pavlov
这会导致垃圾回收出现故障。你能详细说明一下吗? - assylias
1
有些人反对在for循环内使用return。还有其他人反对它,当被问及原因时,他们会编造理由... - cheeken
7
这只是一场宗教战争。 - d1e
6个回答

87
现在有人告诉我,在循环内使用return语句会导致垃圾回收机制失效,这不是很好的编程方式。
那是错误的观念,这也表明你应该对来自那个人的其他建议保持一定的怀疑。
“只有一个return语句”(或更一般地说,只有一个退出点)的口头禅在需要自行管理所有资源的语言中确实很重要——这样你就可以确保将所有清理代码放在一个位置上。
但在Java中,它的用处要小得多:一旦你知道应该返回(以及返回值应该是什么),就直接返回即可。这样更容易阅读——你不必考虑方法的其余部分以确定还会发生什么(除了finally块)。

6
我曾经工作的代码规范中包含了单个return语句。我发现这会导致嵌套很多,使得代码难以阅读。 - brain
3
@brain: 的确。通常情况下,人们采纳一个想法,却不理解为什么在特定的背景下这个想法是一个好主意的原因 - Jon Skeet
1
在异常存在的情况下,单一出口是不可行的,因为几乎任何非平凡代码都可能引发异常。在这里,最好跟随语言的流程,而不是强制代码按照在不同环境/语言中可能有意义的某些规则来执行。 - Ulrich Eckhardt
@JonSkeet,看看你做了什么,有人正在使用这个答案来尝试解决停机问题。 - Kelly S. French

10

现在有人告诉我,这不是很好的编程方式,因为我在循环内使用了return语句,这会导致垃圾回收失效。

那是一派胡言。方法内的所有内容都将被清除,除非在类或其他地方有对其的其他引用(这也是封装很重要的一个原因)。一般来说,最好只使用一个return语句,因为这样更容易确定方法将在何处退出。

个人而言,我会写成:

Boolean retVal = false;
for(int i=0; i<array.length; ++i){
    if(array[i]==valueToFind) {
        retVal = true;
        break; //Break immediately helps if you are looking through a big array
    }
}
return retVal;

10
最好编写易读的代码,无论对于return语句的数量意味着什么。例如,如果有一堆守卫条款,每个(在我看来)应该在失败时立即返回。 - Dave Newton
顺便提一下,这个方法中没有任何需要进行垃圾回收的内容,因为这里没有对象分配。 - Alexander Pavlov
完全同意Dave的观点--我不明白“方法将退出的位置”本身有什么重要性。重要的是你能多容易地跟随方法的逻辑。 - Neil Coffey

4

所有语言中都有提倡在任何函数中使用单个返回语句的方法论。然而,在某些代码中这可能是不可能的,尽管有些人会为此而努力,但这可能会使您的代码更加复杂(比如更多的代码行数),但另一方面,却更容易遵循(比如逻辑流程)。

这不会以任何方式影响垃圾回收!

更好的方法是设置一个布尔值,如果你想听他的话。

boolean flag = false;
for(int i=0; i<array.length; ++i){
    if(array[i] == valueToFind) {
        flag = true;
        break;
    }
}
return flag;

3
有些人认为一个方法应该只有一个出口(比如,只有一个return)。个人认为,试图遵循这个规则会产生更难以阅读的代码。在你的例子中,一旦找到你要找的东西,立即返回它,这是清晰且高效的。 引用C2 wiki: 单个入口和单个出口的原始含义是,它是结构化编程的原始定义的一部分,而不是无纪律的goto SpaghettiCode,并且在此基础上允许进行干净的数学分析。
现在,由于结构化编程早已取得胜利,没有人特别关心这一点了,页面的其余部分主要涉及最佳实践和美学等方面,而不是关于结构化编程构造的数学分析。

2

这段代码在两种情况下都是有效的(即可以编译和执行)。

我大学时的一位讲师告诉我们,在任何循环中,包括 forwhile 循环中使用 continuereturn 语句都是不可取的。原因是当检查代码时,无法立即确定循环的完整长度还是 returncontinue 会生效。

请参见为什么在循环内使用 continue 是一个坏主意? 以获取示例。

需要记住的关键点是,对于像这样简单的场景,这并不重要,但是当您有复杂的逻辑来确定返回值时,如果只有一个返回语句而不是几个,则代码“通常”更易读。

至于垃圾回收方面-我不知道为什么会成为问题。


2

既然没有垃圾回收的问题,我更喜欢这个。

for(int i=0; i<array.length; ++i){
    if(array[i] == valueToFind)
        return true;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接