Сохраняет ли значение str.length() в переменной перед тем, как использовать его в цикле for, какие-либо улучшения производительности в Java?

Короче говоря, JVM внутренне оптимизирует следующий код

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

    for( int i = 0; i < 10; i++)
    {
        a = a + str.length();
    }
}

вести себя так же эффективно, как ниже:

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

    for( int i = 0; i < 10; i++)
    {
        a = a + len;
    }
}

Если он оптимизирует, делает ли это это путем кэширования значения str.length() внутри?

Ответ 1

хороший ответ Эллиот Ф.

Я сделал гораздо более простой тест и использовал два метода с очень большим количеством повторений и каждый раз.

Первый метод (когда длина вычисляется только один раз) был последовательно быстрее второго.

Здесь весь тестовый класс, который я создал,

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();
        }
    }   
}

Результат выглядит следующим образом:

test 1:7
test 2:22

Ответ 2

Я создал следующие два метода:

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();
    }
}

Затем я использовал 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

и для 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

Таким образом, ответ, похоже, будет некоторым преимуществом для хранения длины один раз (он создает более короткий байт-код, эквивалентный 23 против 27 строк), что, кажется, предполагает, что он может работать лучше, но я сомневаюсь, что это действительно может быть измеряется. Особенно после того, как код был скомпилирован JIT).

Наконец, вы можете рассмотреть

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

или просто

int a = 10 * str.length();