哪个循环具有更好的性能? 为什么?

String s = ""; for(i=0;i<....){ s = some Assignment; } 

要么

 for(i=0;i<..){ String s = some Assignment; } 

我再也不需要在循环之外使用's'了。 第一个选项可能更好,因为每次都没有初始化一个新的string。 然而第二个会导致variables的范围被限制在循环本身。

编辑:在回应Milhous的答案。 将String分配给一个循环内的常量是没有意义的。 不,在这里“一些分配”意味着从列表中获得的变化值被迭代。

另外,这个问题不是因为我担心内存pipe理。 只是想知道哪个更好。

有限的范围是最好的

使用你的第二个选项:

 for ( ... ) { String s = ...; } 

范围不影响性能

如果您反汇编每个编译的代码(使用JDK的javap工具),您将看到在这两种情况下循环都编译为完全相同的JVM指令。 还要注意, Brian R. Bondy的 “选项#3”与选项#1相同。 在使用更严格的作用域时,没有额外的内容被添加或从堆栈中移除,并且在这两种情况下都使用相同的数据。

避免过早的初始化

这两种情况唯一的区别在于,在第一个例子中,variabless被不必要地初始化。 这与variables声明的位置是分开的问题。 这增加了两个浪费的指令(加载一个string常量并将其存储在堆栈帧插槽中)。 一个好的静态分析工具会警告你,你永远不会读取你赋值给s值,而且一个好的JIT编译器可能会在运行时将其忽略。

你可以简单地通过使用一个空的声明(即String s; )来解决这个问题,但是这被认为是不好的做法,并且在下面讨论了另一个副作用。

null这样的虚假值通常被分配给一个variables,只是为了避免一个编译器错误,一个variables被读取而不被初始化。 这个错误可以被看作是提示variables作用域太大,并且在需要接收有效值之前声明它。 空的声明迫使你考虑每个代码path; 不要忽略这个有价值的警告,通过分配一个假的值。

节省堆栈槽

如前所述,虽然JVM指令在这两种情况下都是相同的,但是在JVM级别有一个微妙的副作用,使其尽可能使用最有限的范围。 这在方法的“局部variables表”中是可见的。 考虑如果你有多个循环会发生什么情况,variables声明在不必要的大范围内:

 void x(String[] strings, Integer[] integers) { String s; for (int i = 0; i < strings.length; ++i) { s = strings[0]; ... } Integer n; for (int i = 0; i < integers.length; ++i) { n = integers[i]; ... } } 

variablessn可以在它们各自的循环中声明,但是由于它们不是,编译器在栈帧中使用了两个“槽”。 如果它们是在循环中声明的,编译器可以重复使用相同的插槽,使得栈帧更小。

什么真的很重要

但是,这些问题大部分都不重要。 一个好的JIT编译器将会看到,你无法读取你正在浪费地分配的初始值,并优化分配。 在这里或者那里保存一个插槽不会造成或破坏你的应用程序。

重要的是让你的代码易读易维护,在这方面,使用有限的范围显然更好。 variables的范围越小,就越容易理解它的使用方式,以及对代码的任何更改会产生什么样的影响。

理论上讲 ,在循环中声明string是浪费资源的。 然而,在实践中 ,你所提交的两个代码片段将被编译成相同的代码(循环外的声明)。

所以,如果你的编译器做了任何优化,那没有什么区别。

一般来说,我会select第二个,因为's'variables的范围仅限于循环。 优点:

  • 这对程序员来说更好,因为你不必担心函数稍后在某个地方被再次使用
  • 这对于编译器来说更好,因为variables的范围较小,所以它可以做更多的分析和优化
  • 这对于未来的读者来说更好,因为他们不会理解为什么variables在循环之外被声明,如果以后再也不用的话

如果你想加快循环,我宁愿在计数器旁边声明一个最大variables,这样就不需要重复查找条件:

代替

 for (int i = 0; i < array.length; i++) { Object next = array[i]; } 

我更喜欢

 for (int i = 0, max = array.lenth; i < max; i++) { Object next = array[i]; } 

任何其他应该考虑的事情已经被提及,所以只有我的两分钱(见埃里克森邮报)

Greetz,GHad

要添加一点到@ Esteban Araya的答案 ,他们都需要创build一个新的string每次通过循环(作为some Assignmentexpression式的返回值)。 这些string需要被垃圾收集。

我知道这是一个古老的问题,但我想我会添加一点, 有点相关。

我注意到,浏览Java源代码时,一些方法,如String.contentEquals(下面重复)使冗余本地variables,只是类variables的副本。 我相信在某处有一个评论,这意味着访问局部variables比访问类variables要快。

在这种情况下,“v1”和“v2”似乎是不必要的,为了简化代码,可以将其消除,但为了提高性能,还可以加上代码。

 public boolean contentEquals(StringBuffer sb) { synchronized(sb) { if (count != sb.length()) return false; char v1[] = value; char v2[] = sb.getValue(); int i = offset; int j = 0; int n = count; while (n-- != 0) { if (v1[i++] != v2[j++]) return false; } } return true; } 

在我看来,我们需要更多的问题说明。

 s = some Assignment; 

没有规定这是什么样的任务。 如果分配是

 s = "" + i + ""; 

那么需要分配一个新的刺。

但如果是的话

 s = some Constant; 

只会指向常量的内存位置,因此第一个版本会更有效率。

似乎我有点傻,担心为一个解释浪漫恕我直言循环的优化。

当我使用multithreading(50 +),然后我发现这是一个非常有效的方式处理幽灵线程问题与不能够正确closures进程….如果我错了,请让我知道为什么我错了:

 Process one; BufferedInputStream two; try{ one = Runtime.getRuntime().exec(command); two = new BufferedInputStream(one.getInputStream()); } }catch(e){ e.printstacktrace } finally{ //null to ensure they are erased one = null; two = null; //nudge the gc System.gc(); }