Viv*_*ira 50 java string performance garbage-collection
String s = "";
for(i=0;i<....){
s = some Assignment;
}
Run Code Online (Sandbox Code Playgroud)
要么
for(i=0;i<..){
String s = some Assignment;
}
Run Code Online (Sandbox Code Playgroud)
我不需要再次在循环外使用's'了.第一个选项可能更好,因为每次都不会初始化新的String.然而,第二个将导致变量的范围限于循环本身.
编辑:回应Milhous的回答.将String分配给循环中的常量是没有意义的吗?不,这里'一些分配'意味着从迭代的列表中获得的变化值.
此外,问题不是因为我担心内存管理.只是想知道哪个更好.
eri*_*son 108
使用您的第二个选项:
for ( ... ) {
String s = ...;
}
Run Code Online (Sandbox Code Playgroud)
如果你反编译每个编译的代码(使用JDK的javap工具),你会发现循环在两种情况下编译成完全相同的JVM指令.另请注意,Brian R. Bondy的 "选项#3"与选项#1相同.使用更紧密的范围时,不会在堆栈中添加或删除任何额外内容,并且在两种情况下都在堆栈上使用相同的数据.
这两种情况的唯一区别在于,在第一个示例中,变量s被不必要地初始化.这是与变量声明的位置不同的问题.这会添加两条浪费的指令(加载字符串常量并将其存储在堆栈帧插槽中).一个好的静态分析工具会警告你,你永远不会读取你赋予的值s,而一个好的JIT编译器可能会在运行时忽略它.
你可以简单地通过使用一个空声明来解决这个问题(即String s;),但这被认为是不好的做法,并且下面讨论了另一个副作用.
通常将伪造的值null分配给变量只是为了避免编译器错误,即读取变量而不进行初始化.此错误可以视为变量作用域太大,并且在需要接收有效值之前声明它.空声明强制您考虑每个代码路径; 不要通过指定虚假值来忽略这个有价值的警告.
如上所述,虽然JVM指令在两种情况下都是相同的,但是有一个微妙的副作用,使得在JVM级别最好使用尽可能最有限的范围.这在方法的"局部变量表"中可见.考虑如果你有多个循环会发生什么,变量在不必要的大范围内声明:
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];
...
}
}
Run Code Online (Sandbox Code Playgroud)
变量s和n可以各自循环内部声明,但由于他们都没有,编译器使用堆栈帧两个"插槽".如果它们在循环内声明,则编译器可以重用相同的槽,使堆栈帧更小.
但是,大多数这些问题并不重要.一个好的JIT编译器将会看到无法读取您浪费分配的初始值,并优化分配.在这里或那里保存一个插槽不会决定你的应用程序.
重要的是使您的代码可读且易于维护,在这方面,使用有限的范围显然更好.变量具有的范围越小,就越容易理解它的使用方式以及对代码的任何更改会产生什么影响.
Est*_*aya 22
从理论上讲,在循环中声明字符串是浪费资源.但实际上,您提供的两个片段都将编译为相同的代码(循环外的声明).
因此,如果您的编译器进行了任何数量的优化,那么没有区别.
Gre*_*ill 17
一般来说,我会选择第二个,因为's'变量的范围仅限于循环.优点:
如果你想加速循环,我更喜欢在计数器旁边声明一个max变量,这样就不需要重复查找condidtion了:
代替
for (int i = 0; i < array.length; i++) {
Object next = array[i];
}
Run Code Online (Sandbox Code Playgroud)
我更喜欢
for (int i = 0, max = array.lenth; i < max; i++) {
Object next = array[i];
}
Run Code Online (Sandbox Code Playgroud)
任何其他应该考虑的事情都已经提到了,所以只需要我的两分钱(见erickons帖子)
格雷茨,GHad