在 for 循环条件下重复调用 getter

Repeatedly calling getter in for-loop condition

哪个循环更快,有区别吗?

final int cSize = getSize();
for(lineCount = 0; lineCount <= cSize; lineCount++) {
   // Do something!
}

for(lineCount = 0; linecount <= getSize(); lineCount++) {
   // Do something!
}

其中 getSize() 是一个简单的 getter:

private int getSize() {
   return this.size;
}

假设this.size不是最终的,这两个循环有不同的语义:

  • 第一个循环不会对循环内完成的 size 中的更改做出反应;它将根据 cSize 变量的要求执行多次。
  • 第二个循环将对 size 的更改做出反应。如果 size 增加或减少,循环迭代次数也会增加或减少。

就性能而言,Java 的即时编译器足够聪明,可以直接使用 this.size 变量,有效地绕过 getter。这会产生非常相同的性能。

使用此示例测试不同的 for 循环:

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

public class ForLoopPerformanceTest {
private static List<Integer> list = new ArrayList<>();
private static long startTime;
private static long endTime;

static {
    for (int i = 0; i < 1_00_00_000; i++) {
        list.add(i);
    }
}

@SuppressWarnings("unused")
public static void main(String[] args) {
    // Type 1
    startTime = Calendar.getInstance().getTimeInMillis();
    for (Integer i : list) {
        //
    }
    endTime = Calendar.getInstance().getTimeInMillis();
    System.out.println("For each loop :: " + (endTime - startTime) + " ms");

    // Type 2
    startTime = Calendar.getInstance().getTimeInMillis();
    for (int j = 0; j < list.size(); j++) {
        //
    }
    endTime = Calendar.getInstance().getTimeInMillis();
    System.out.println("Using collection.size() :: " + (endTime - startTime) + " ms");

    // Type 3
    startTime = Calendar.getInstance().getTimeInMillis();
    int size = list.size();
    for (int j = 0; j < size; j++) {
        // System.out.println(j);
    }
    endTime = Calendar.getInstance().getTimeInMillis();
    System.out.println(
            "Using [int size = list.size(); int j = 0; j < size ; j++] :: " + (endTime - startTime) + " ms");

    // Type 4
    startTime = Calendar.getInstance().getTimeInMillis();
    for (int j = list.size(); j > size; j--) {
        // System.out.println(j);
    }
    endTime = Calendar.getInstance().getTimeInMillis();
    System.out.println("Using [int j = list.size(); j > size ; j--] :: " + (endTime - startTime) + " ms");
}
}

The Results

对于每个循环:: 108 毫秒

使用 collection.size() :: 39 毫秒

使用[int size = list.size();整数 j = 0; j < 大小; j++] :: 4 毫秒

使用[int j = list.size(); j > 大小; j--] :: 0 毫秒