Beware of such micro-benchmark. Often, the compiler can compile away some code it sees as no-op, and either the JIT compiler hasn't time to kick in, or it might optimize away other code...
For reliable benchmarks, I now use Caliper (at GoogleCode). It avoids such pitfalls and ease testing.
I made a little bench, with the following code:
- class BenchmarkTester
- {
- public static final int SIZE = 10000;
- public ArrayList<String> stuff = new ArrayList<String>(SIZE);
- public void init()
- {
- System.out.println("Init");
- for (int i = 0; i < SIZE; i++)
- {
- stuff.add("Test " + i);
- }
- }
- public boolean check1()
- {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < SIZE; i++)
- {
- String el = stuff.get(i);
- sb.append(el);
- }
- //~ return true;
- return sb.length() > 0;
- }
- public boolean check2()
- {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < stuff.size(); i++)
- {
- String el = stuff.get(i);
- sb.append(el);
- }
- //~ return true;
- return sb.length() > 0;
- }
- public boolean check3()
- {
- StringBuilder sb = new StringBuilder();
- for (int i = 0, s = stuff.size(); i < s; i++)
- {
- String el = stuff.get(i);
- sb.append(el);
- }
- //~ return true;
- return sb.length() > 0;
- }
- public boolean check4()
- {
- StringBuilder sb = new StringBuilder();
- for (String str : stuff)
- {
- String el = str;
- sb.append(el);
- }
- //~ return true;
- return sb.length() > 0;
- }
- }
and the corresponding Caliper code test.
I tested with and without the StringBuilder code.
Indeed, without it, the for-each loop takes roughly twice the time of the pure numerical loop.
0% Scenario{vm=java, trial=0, benchmark=Checking1} 108278,19 ns; ?=712,28 ns @ 3 trials
25% Scenario{vm=java, trial=0, benchmark=Checking2} 113503,43 ns; ?=1079,27 ns @ 9 trials
50% Scenario{vm=java, trial=0, benchmark=Checking3} 108921,51 ns; ?=981,37 ns @ 3 trials
75% Scenario{vm=java, trial=0, benchmark=Checking4} 270592,54 ns; ?=5980,26 ns @ 10 trials
benchmark us logarithmic runtime
Checking1 108 =
Checking2 114 ==
Checking3 109 =
Checking4 271 ==============================
But with it, the time spent in the loop logic is reduced with regard to the overall time to do a loop, and the advantage is reduced.
0% Scenario{vm=java, trial=0, benchmark=Checking1} 569319,86 ns; ?=5852,04 ns @ 10 trials
25% Scenario{vm=java, trial=0, benchmark=Checking2} 567657,56 ns; ?=4089,58 ns @ 3 trials
50% Scenario{vm=java, trial=0, benchmark=Checking3} 567690,92 ns; ?=5310,11 ns @ 3 trials
75% Scenario{vm=java, trial=0, benchmark=Checking4} 721832,85 ns; ?=4979,20 ns @ 3 trials
benchmark us logarithmic runtime
Checking1 569 =
Checking2 568 =
Checking3 568 =
Checking4 722 ==============================
In general, you do more or less complex stuff in a loop, so the time spent in the loop logic is probably neglectful.
Often, the advantage of the advanced loop syntax override the loss of time.
Note that some other structures, like LinkedList, might even be faster with such loop (as we keep a current position in the list).