在for循环中使用str.length()值之前将它存储在变量中是否会在Java中进行任何性能改进?

dee*_*pak 10 java jvm

简而言之,JVM是否在内部优化了以下代码

public void test(String str)
{
    int a = 0;

    for( int i = 0; i < 10; i++)
    {
        a = a + str.length();
    }
}
Run Code Online (Sandbox Code Playgroud)

表现得如下:

public void test(String str)
{
    int len = str.length();
    int a = 0;

    for( int i = 0; i < 10; i++)
    {
        a = a + len;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果它确实优化了,它是通过在内部缓存str.length()值来实现的吗?

Ell*_*sch 6

我创建了以下两种方法,

public void test(String str) {
    int len = str.length();
    int a = 0;
    for (int i = 0; i < 10; i++) {
        a = a + len;
    }
}

public void test2(String str) {
    int a = 0;
    for (int i = 0; i < 10; i++) {
        a = a + str.length();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我习惯javap -v为第一种方法生成test

  public void test(java.lang.String);
    descriptor: (Ljava/lang/String;)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=5, args_size=2
         0: aload_1
         1: invokevirtual #16                 // Method java/lang/String.length:()I
         4: istore_2
         5: iconst_0
         6: istore_3
         7: iconst_0
         8: istore        4
        10: goto          20
        13: iload_3
        14: iload_2
        15: iadd
        16: istore_3
        17: iinc          4, 1
        20: iload         4
        22: bipush        10
        24: if_icmplt     13
        27: return
Run Code Online (Sandbox Code Playgroud)

并为 test2

  public void test2(java.lang.String);
    descriptor: (Ljava/lang/String;)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=4, args_size=2
         0: iconst_0
         1: istore_2
         2: iconst_0
         3: istore_3
         4: goto          17
         7: iload_2
         8: aload_1
         9: invokevirtual #16                 // Method java/lang/String.length:()I
        12: iadd
        13: istore_2
        14: iinc          3, 1
        17: iload_3
        18: bipush        10
        20: if_icmplt     7
        23: return
Run Code Online (Sandbox Code Playgroud)

所以答案似乎是存储长度一次有一些优势(它产生更短的字节码,相当于23对27线)这似乎表明它可能表现更好,但我怀疑它实际上可以测量.特别是在代码被JIT编译之后).

最后,您可以考虑一下

public void test(String str)
{
  int a = 0;
  for( int i = 0, len = str.length(); i < 10; i++) {
    a = a + len;
  }
}
Run Code Online (Sandbox Code Playgroud)

要不就

int a = 10 * str.length();
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢你指出避免微观优化,但我个人认为这是一个"自由优化",在我看来,在某些情况下可以增加清晰度.只要你对范围等合理,我认为声明一个变量来保存那个值并没有什么不妥,我特别认为在`string.length()的时候养成习惯是没有错的.是`someObject.someDeceptiveSometimesSlowCallThatOccassionallyChecksInOnTheCaymanIslands()`. (2认同)

gts*_*101 6

很好的答案Elliot F.

我做了一个更简单的测试,并且运行了两个方法,重复次数非常多并且每个方法都有时间.

第一种方法(其中长度仅计算一次)始终比第二种方法快.

这是我创建的整个测试类;

package _testing;

import java.util.Date;

public class Speed {

    long count = 5000000;
    public static void main(String[] args) {

        long start, finish; 
        Speed sp = new Speed(); 

        start = new Date().getTime();
        sp.test("test");
        finish = new Date().getTime();
        System.out.println("test 1:"+(finish - start));

        start = new Date().getTime();
        sp.test2("test");
        finish = new Date().getTime();
        System.out.println("test 2:"+(finish - start));

    }


    public void test(String str) {
        int len = str.length();
        int a = 0;
        for (int i = 0; i < count; i++) {
            a = a + len;
        }
    }

    public void test2(String str) {
        int a = 0;
        for (int i = 0; i < count; i++) {
            a = a + str.length();
        }
    }   
}
Run Code Online (Sandbox Code Playgroud)

输出看起来像这样;

test 1:7
test 2:22
Run Code Online (Sandbox Code Playgroud)

  • 我真的很喜欢你写了一个基准.并且它确实表明它是一个真正可测量的差异,**但**我会指出你已经*观察到*〜(3/5000000)x'的差异,这并没有让我觉得具有统计意义. (3认同)