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

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

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

我再也不需要在循环外使用s"了.第一个选项可能更好,因为每次都不会初始化新的字符串.然而,第二个会导致变量的范围被限制在循环本身.

I don't need to use 's' outside the loop ever again. The first option is perhaps better since a new String is not initialized each time. The second however would result in the scope of the variable being limited to the loop itself.

回应 Milhous 的回答.将字符串分配给循环内的常量是没有意义的,不是吗?不,这里的一些分配"是指从被迭代的列表中获得的变化值.

In response to Milhous's answer. It'd be pointless to assign the String to a constant within a loop wouldn't it? No, here 'some Assignment' means a changing value got from the list being iterated through.

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

Also, the question isn't because I'm worried about memory management. Just want to know which is better.

推荐答案

Limited Scope is Best

使用第二个选项:

Limited Scope is Best

Use your second option:

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

范围不影响性能

如果您反汇编从每个编译的代码(使用 JDK 的 javap 工具),您将看到循环在两种情况下都编译为完全相同的 JVM 指令.另请注意 BrianR. Bondy 的选项#3"与选项#1 相同.使用更紧凑的范围时,不会从堆栈中添加或删除任何额外的内容,并且在两种情况下都在堆栈上使用相同的数据.

Scope Doesn't Affect Performance

If you disassemble code the compiled from each (with the JDK's javap tool), you will see that the loop compiles to the exact same JVM instructions in both cases. Note also that Brian R. Bondy's "Option #3" is identical to Option #1. Nothing extra is added or removed from the stack when using the tighter scope, and same data are used on the stack in both cases.

这两种情况的唯一区别是,在第一个示例中,变量 s 被不必要地初始化.这是与变量声明位置不同的问题.这增加了两条浪费的指令(加载字符串常量并将其存储在堆栈帧槽中).一个好的静态分析工具会警告您,您永远不会读取您分配给 s 的值,并且一个好的 JIT 编译器可能会在运行时忽略它.

The only difference between the two cases is that, in the first example, the variable s is unnecessarily initialized. This is a separate issue from the location of the variable declaration. This adds two wasted instructions (to load a string constant and store it in a stack frame slot). A good static analysis tool will warn you that you are never reading the value you assign to s, and a good JIT compiler will probably elide it at runtime.

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

You could fix this simply by using an empty declaration (i.e., String s;), but this is considered bad practice and has another side-effect discussed below.

通常将像 null 这样的虚假值分配给变量,只是为了消除编译器错误,即读取变量但未初始化.这个错误可以被认为是变量范围太大的提示,并且它在需要接收有效值之前被声明.空声明迫使您考虑每个代码路径;不要通过分配虚假值来忽略这个有价值的警告.

Often a bogus value like null is assigned to a variable simply to hush a compiler error that a variable is read without being initialized. This error can be taken as a hint that the variable scope is too large, and that it is being declared before it is needed to receive a valid value. Empty declarations force you to consider every code path; don't ignore this valuable warning by assigning a bogus value.

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

As mentioned, while the JVM instructions are the same in both cases, there is a subtle side-effect that makes it best, at a JVM level, to use the most limited scope possible. This is visible in the "local variable table" for the method. Consider what happens if you have multiple loops, with the variables declared in unnecessarily large scope:

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];
    ...
  }
}

变量 sn 可以在它们各自的循环中声明,但由于它们不是,编译器在堆栈帧中使用两个槽".如果它们在循环内声明,编译器可以重用相同的槽,从而使堆栈帧更小.

The variables s and n could be declared inside their respective loops, but since they are not, the compiler uses two "slots" in the stack frame. If they were declared inside the loop, the compiler can reuse the same slot, making the stack frame smaller.

但是,这些问题大多无关紧要.一个好的 JIT 编译器会发现无法读取您浪费分配的初始值,并优化分配.在这里或那里保存一个槽不会成败您的应用程序.

However, most of these issues are immaterial. A good JIT compiler will see that it is not possible to read the initial value you are wastefully assigning, and optimize the assignment away. Saving a slot here or there isn't going to make or break your application.

重要的是让您的代码可读且易于维护,在这方面,使用有限范围显然更好.变量的作用域越小,就越容易理解它的使用方式以及对代码的任何更改都会产生什么影响.

The important thing is to make your code readable and easy to maintain, and in that respect, using a limited scope is clearly better. The smaller scope a variable has, the easier it is to comprehend how it is used and what impact any changes to the code will have.

相关文章