【问题标题】:Why is it bad to change for loop counter in Java?为什么在 Java 中更改循环计数器不好?
【发布时间】:2017-02-28 21:39:33
【问题描述】:

我经常听说在 for 循环体中修改循环计数器是不好的。下面的(坏的)例子说明了我在说什么。

for (int i=0; i<10; i++) {
    i++;
}

我知道这在 while 循环中是允许的,但任何人都可以解释为什么这在 Java 中是一种不好的做法。甚至是任何编程语言的问题。

【问题讨论】:

  • 这很糟糕,因为您无法仅通过查看条件来确定您将通过多少次循环,从而使维护变得更加困难。归结为可读性。但是没有什么明确不允许的。
  • 感谢您的快速回复。是否会出现有关软件或 Java VM 功能的任何问题?我听说过其他编程语言的问题。你有这方面的例子吗?
  • 在 Java 或其他 C 派生语言 AFAIK 中没有。如果条件正确,则不会。但是,您可能会遇到相等问题(例如:for (int i=0; i==10; i++) { i+=10; }),或者如果您在循环中增加但在正文中减少(例如:for (int i=0; i&lt;10; i++) { i--; })。如果您正在遍历一个数组,并在读取之前更改索引,这可能会导致抛出异常。
  • Thomas 我建议你在他的 cmets 中听听@AntonH 的建议,他们都很好!

标签: java loops for-loop while-loop programming-languages


【解决方案1】:

看看这段代码会发生什么:

1 for (int i=0; i<10; i++) {
2     i++;
3 }
  1. 最初第 1 行 i=0。
  2. 第 2 行增加 i,现在等于 1。
  3. 循环结束,所以 i++ 生效,现在 i=2。
  4. 等等……

所以如果你真的想做这样的事情,你可以这样写:

for (int i=0; i<10; i+=2) {
}

得到相同的结果。不一定是坏代码,但这样写代码没有意义,而且很难排查。

【讨论】:

  • 在第二个循环中,我想你的意思是i+=2
  • 好的,但是如果您只想在某些情况下将计数器增加两次,但默认情况下只增加一次呢?
  • @ThomasMaier 然后你使用if
  • 是的,这对于第一个解决方案是可能的,但对于第二个解决方案是不可能的,对吧?
  • @ThomasMaier 正确。尽管您有第二个拥有for (int i=0; i&lt;10; i+=2) { if(someCondition) { i--; } } 的可能性。是的,它很丑,但功能相似。我真的不能更准确,因为我真的不知道你想要完成什么。
【解决方案2】:

主要是因为大多数程序员都是这样使用它的,所以正如@AntonH 提到的那样,它对每个人都更具可读性。

旁注:尝试使用其他语言(如果有记忆,如 C)来编写:

for(int i =0; i< 10; i){
        printf("%d", i);
        i++;
    }

此代码编译并运行。在 Java 中,等价物:

for(int i =0; i< 10; i){
        System.out.println("%d", i);
        i++;
    }

感谢@David Wallace 编辑:这会产生编译错误,必须在 for 循环的语句部分进行赋值。

【讨论】:

  • 其实你的Java sn-p中的两个编译错误不是你说的原因。在 Java 中递增或递减迭代器变量是完全合法的。
  • 是的。我写了“to not”,就像你不允许在 for 循环的语句部分使用非递增(或递减)变量,而不是 C 语言。我不赞成这种模棱两可的说法。
  • 抱歉,我看错了。但是,实际上,不增加或减少迭代器变量也是合法的。所以虽然我看错了你的句子,但它仍然是错误的。如果您在for 语句的第三个子句中提供某些内容,则它必须是赋值,但不一定是递增或递减。例如,for(int i = 0; i &lt; 10; i = 0) 是合法的。
  • 很公平,实际上我并没有意识到这一点,因为在 Oracle 网站上,他们称该语句为“增量”(参见 docs.oracle.com/javase/tutorial/java/nutsandbolts/for.html)。谢谢,我学到了一件有趣的事情。
  • for 中不需要第三个子句。
【解决方案3】:

这不好的两个原因:

  1. 可读性。 for( a; b; c ) { d; }a; while( b ) { d; c; } 的简写,明确用于迭代列表的情况。它在语言中不是严格需要的。拥有它的全部意义在于暗示意图:“我想遍历整个列表”或“我想按顺序遍历列表的一部分,然后在找到某些内容时中止”。

    如果您添加一个额外的增量,这会让其他遇到您的代码的人感到惊讶。如果你上面的c++x 或其他什么,人们会简单地假设它遍历所有项目,然后找到“惊喜!并非总是如此!”。

    OTOH,如果您使用 while 循环,人们只会看到条件,并被警告这将是一个更复杂的循环,其中增量不会是恒定的。

  2. 优化。鉴于上述意图声明,一些优化器将为for 语句生成与while 语句不同的代码。尽管它们都不应该生成错误的代码,但它们可能会应用一种优化,这种优化对于非顺序访问的性能特征比顺序访问更差。

    “更糟糕的性能特征”是指它们可能会告诉 CPU 缓存错误的代码路径并减慢你的执行速度,因为在不必要地刷新数据后可能必须再次将数据加载到 CPU 中.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-11
    • 1970-01-01
    • 2016-02-27
    • 2018-01-18
    • 2019-05-30
    • 2010-09-11
    • 1970-01-01
    相关资源
    最近更新 更多