从理论上讲,在循环中声明字符串是浪费资源.但实际上,您提供的两个片段都将编译为相同的代码(循环外的声明).
因此,如果您的编译器进行了任何数量的优化,那么没有区别.
使用您的第二个选项:
for ( ... ) { String s = ...; }
如果你反编译每个编译的代码(使用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]; ... } }
变量s
和n
可以各自循环内部声明,但由于他们都没有,编译器使用堆栈帧两个"插槽".如果它们在循环内声明,则编译器可以重用相同的槽,使堆栈帧更小.
但是,大多数这些问题并不重要.一个好的JIT编译器将会看到无法读取您浪费分配的初始值,并优化分配.在这里或那里保存一个插槽不会决定你的应用程序.
重要的是使您的代码可读且易于维护,在这方面,使用有限的范围显然更好.变量具有的范围越小,就越容易理解它的使用方式以及对代码的任何更改会产生什么影响.
从理论上讲,在循环中声明字符串是浪费资源.但实际上,您提供的两个片段都将编译为相同的代码(循环外的声明).
因此,如果您的编译器进行了任何数量的优化,那么没有区别.
一般来说,我会选择第二个,因为's'变量的范围仅限于循环.优点:
这对程序员来说更好,因为你不必担心在函数后面的某个地方再次使用's'
这对编译器来说更好,因为变量的范围较小,因此可以进行更多的分析和优化
这对于未来的读者来说更好,因为他们不会想知道为什么's'变量在循环之外被声明,如果它以后从未使用过
如果你想加速循环,我更喜欢在计数器旁边声明一个max变量,这样就不需要重复查找condidtion了:
代替
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]; }
任何其他应该考虑的事情都已经提到了,所以只需要我的两分钱(见erickons帖子)
格雷茨,GHad