【问题标题】:Advantages and disadvantages of declaring a variable at the for loop?在 for 循环中声明变量的优缺点?
【发布时间】:2017-02-24 05:59:25
【问题描述】:

在for循环中声明一个变量有什么好处和坏处?? 我想改变我的讲师的想法,或者改变我的想法,关于这个: 讲师强迫我使用:

// Declare variables
int i;
...

for(i = 0; boolen expesion; update)   // Note i not declared here

我喜欢做:

for(int i = 0; boolean expesion; update)   // Note i is declared here

在考试中,按照自己的方式做事会被扣分。我试图通过告诉他来说服他:

  • 我没有看到代码按照他的方式完成。
  • 它不是那么重要的变量,所以让它在本地有意义。
  • 在 for 循环中可能需要使用 long 类型的变量。

他的回答是:“如果这里的循环很少,你不需要重复声明相同的变量”。很难与讲师争论,因为你是来自外国国家的一年级学生。但是 int 并没有占用太多内存,而且 java 有一个垃圾收集器来清理内存..

所以请帮我用一个好的论据说服他或我。

【问题讨论】:

  • 不要和他争论。做他让你做的事,考试后做你想做的事。
  • 如果有多个循环,这是有益的,尽管考虑到现代机器,这种好处非常小。 GC 也不是问题 - 如果以后不使用变量,JVM 通常足够聪明,可以对变量进行 GC。这个问题/论点就像大象身上的抓痕。
  • 也许他曾经用旧的 C 语言编程? (例如:在 C99 之前)那时你必须这样做。虽然不值得争论,但我也更喜欢第二种风格(因为编译器通常能够优化代码)
  • 我同意并想添加第二种方式可以添加轻微micro optimization
  • 1.讲师永远是对的。 2. 如果讲师不正确,请参阅 1. 考试后忘记在 80' 中编程学习,其中节省的几个字节至关重要。

标签: java variables for-loop


【解决方案1】:

评论说的很对“不要和他争论。按照他的要求做,考试后做你想做的事。”

但是,您的教授确实对何时有效,并且应该这样做,我假设您遗漏了。例如,通过将索引变量留在 for 循环的范围之外,您可以稍后引用它。 (当数组从未知来源传入时,这对于确定数组的大小非常有用,例如提取数据库)。同样,在每次运行循环时不必设置新变量(通过将 i 设置回零,但这取决于语言,但在汇编设置中我可以看到一些寻址和 push/pop/ext ... CPU 上的值)。

但是,在大多数情况下......除了一些非常低级别的处理收益(这是有争议的)之外,没有真正的好处。我假设您的教授要么是一位在该行业工作多年的低端程序员,要么受过良好教育,要么具有高开销应用程序的经验。

【讨论】:

  • 你打算如何使用 for 循环迭代一个未知大小的数组?如果您的意思是迭代直到下一个元素是null,那么使用一段时间会更惯用(因此不适用于该问题)。第二点实际上已在@NickBelle 链接的问题中得到解决,其中在 for 循环中声明变量实际上具有最低限度的更好性能(因为您通常只将计数器变量保存在寄存器中)。不幸的是,成为教授并不意味着您受过教育和/或经验丰富。
  • 对所有这些都是正确的,但假设最好的情况是有时您的教授是正确的,那就是答案(在一般意义上 - 他不是)。您可以将数组的静态上限用于 for 循环(例如,您将获得的最大大小是 1000 个元素)并在元素为空或达到限制时中断。通过这样做,您可以通过仅使用 2 个元素(I,Upperlimit)来获得一个循环的最大值,并准确地知道时间性能是多少。我可以看到这在时间是绝对的硬件中很有用。
【解决方案2】:

他的回答是:“如果这里有几个循环,你不需要 重复声明同一个变量”.. 很难反驳 讲师很特别,那么你是一个外国语系的一年级学生 国家。但是 int 并没有占用那么多内存加上 java 有垃圾 收集器清理内存..

这是一个关于在学术界学习编写软件的丑陋事实。除非你的系主任不仅比大多数讲师更好,而且在为学生辩护时表现得自信,否则你只会降低你的成绩。当我上大学时,一位教授因使用“先进技术”而给学生打分而享有盛誉。我的意思是在他讲课之前的章节。即使他们能够以绝对精确的方式充分表达他们正在做的事情,这表明他们不仅仅是在复制和粘贴。

事实上,您的教授对于大多数常见循环都是错误的。除非您的代码需要在循环之后稍后引用索引变量,否则最好让变量随着范围的变化而被删除。对于大多数实际循环,他的方式不仅没有必要。这甚至是不可能的,因为今天很多“for”循环实际上是这样的 for-each 循环

for (String s : someArray) {
    System.out.println(s);
}

或(Groovy)

someArray.each { element ->
    println element
}

更新:我认为教授的论点非常错误的另一件事是,除非绝对必要,否则公开状态通常是不好的形式。作为一般规则,这对于任何语言来说都是一个糟糕的想法,尤其是对于垃圾收集的语言。由于变量是int 而不是Integer(对于阅读本文的初学者来说,是堆栈上的原始变量与堆上的对象),因此在这种情况下它不太重要。然而,在处理对象时,编写代码时应该着眼于让 GC 说“这个范围已经退出,让我们清理其中的所有内容”变得微不足道。

随着时间的推移,如果您习惯于保留不必要的状态,您就会冒着引入内存泄漏的风险。您的习惯可能会使 GC 更难完成其工作和长时间运行的任务,这会导致内存需求增加和不稳定。无论如何你都不需要去纯粹的函数式语言,但你需要借用它的精神,即认为状态是必要的邪恶,而不是来自天堂的祝福。

【讨论】:

  • 我被 “int 没有占用这么多内存加上 java 有垃圾收集器”所困,因为局部原始变量是在 stack,而不是 heap,因此不受垃圾收集器的控制。此外,由于为局部变量留出的堆栈空间在变量范围结束时变得可重用,因此在未嵌套的 for 循环中声明多个 int 变量实际上将重用该空间,而不管变量名称如何。
  • @Andreas GC 意味着 所有 变量都被垃圾回收似乎是一个常见的误解(尤其是在初学者中)。他们中的许多人也不知道堆栈和堆之间的区别(可能是因为这种误解或者只是缺乏知识)
  • @Andreas 感谢您指出这一点。我有点知道,这更像是听说过堆栈和堆。这个post 帮助我了解更多。特别是评论“因为一个对象只在堆和堆栈中创建,主要包含一个局部变量,一旦它们失去作用域就会被清除”。一些更有用的info,以防将来的读者需要。
  • @UnholySheep 。感谢您的评论。是缺乏知识。我是一年级学生:)
【解决方案3】:

他说得对,你不需要重复声明同一个变量,但是:

  • 最好将变量的范围限制在使用它们的位置。

  • 单独声明变量实际上需要多行源代码,所以它本身并没有减少代码。

  • 在每个for 循环中声明变量将不会使用更多空间。

  • 生成的字节码是一样的。

因此,如果您不需要在for 循环之外 的变量,则应始终在for 循环的范围内声明该变量。有助于防止意外将变量用于其他目的。

让我们看下面的代码:

static void test1() {
    int i;
    for (i = 0; i < 10; i++)
        ;
    for (i = 0; i < 10; i++)
        ;
}
static void test2() {
    for (int i = 0; i < 10; i++)
        ;
    for (int i = 0; i < 10; i++)
        ;
}

如您所见,单独声明 i 需要多一行代码。

字节码是这样的:

static void test1();               static void test2();
  Code:                              Code:
     0: iconst_0                        0: iconst_0
     1: istore_0                        1: istore_0
     2: goto          8                 2: goto          8
     5: iinc          0, 1              5: iinc          0, 1
     8: iload_0                         8: iload_0
     9: bipush        10                9: bipush        10
    11: if_icmplt     5                11: if_icmplt     5
    14: iconst_0                       14: iconst_0
    15: istore_0                       15: istore_0
    16: goto          22               16: goto          22
    19: iinc          0, 1             19: iinc          0, 1
    22: iload_0                        22: iload_0
    23: bipush        10               23: bipush        10
    25: if_icmplt     19               25: if_icmplt     19
    28: return                         28: return

如您所见,它们完全相同,因此它们在堆栈上为局部变量使用相同数量的空间。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-28
    • 1970-01-01
    • 1970-01-01
    • 2015-03-25
    • 1970-01-01
    相关资源
    最近更新 更多