On 04/04/2008 at 4:40 AM, Toke Eskildsen wrote: > On Wed, 2008-04-02 at 09:30 -0400, Mark Miller wrote: > > > - replacement of indexed for loops with for each constructs > > > > Is this always the best idea? Doesn't the for loop construct make an > > iterator, which can be much slower than an indexed for loop? > > Only in the case of iterations over collections. For arrays, the foreach > is syntactic sugar for indexed for-loop. > http://java.sun.com/docs/books/jls/third_edition/html/statements.html#14.14.2
I don't think this is actually true. The text at the above-linked page simply says that for-each over an array "means the same as" an indexed loop over the same array. "Syntactic sugar", OTOH, implies that the resulting opcode is exactly the same. When I look at the byte code (using javap) for the comparison test I include below, I can see that the indexed and for-each loops do not generate the same byte code. I constructed a simple program to compare the runtime length of the two loop control mechanisms, while varying the size of the array. The test program takes command line parameters to control which loop control mechanism to use, the size of the array (#elems), and the number of times to execute the loop (#iters). I used a Bash shell script to invoke the test program. Summary of the results: over int[] arrays, indexed loops are faster on arrays with fewer than about a million elements. The fewer the elements, the faster indexed loops are relative to for-each loops. This could be explained by a higher one-time setup cost for the for-each loop - above a certain array size, the for-each setup cost is lost in the noise. It should be noted, however, that this one-time setup cost is quite small, and might be worth the increased code clarity. Here are the results for three different platforms: - Best of five iterations for each combination - All using the -server JVM option - Holding constant #iters * #elems = 10^10 - Rounding the reported real time to the nearest tenth of a second - "% Slower" = 100 * ((For-each - Indexed) / Indexed) Platform #1: Windows XP SP2; Intel Core 2 duo [EMAIL PROTECTED]; Java 1.5.0_13 #iters #elems For-each Indexed % Slower ------ ------ -------- ------- -------- 10^9 10^1 22.3s 13.8s 62% 10^8 10^2 16.0s 13.6s 18% 10^6 10^4 14.8s 13.0s 14% 10^4 10^6 12.9s 12.9s 0% 10^3 10^7 13.4s 13.3s 1% Platform #2: Debian Linux, 2.6.21.7 kernel; Intel Xeon [EMAIL PROTECTED]; Java 1.5.0_14 #iters #elems For-each Indexed % Slower ------ ------ -------- ------- -------- 10^9 10^1 33.6s 14.2s 137% 10^8 10^2 20.4s 13.9s 47% 10^6 10^4 19.0s 12.7s 50% 10^4 10^6 12.7s 12.8s -1% 10^3 10^7 13.2s 13.2s 0% Platform #3: Debian Linux, 2.6.21.7 kernel; Intel Xeon [EMAIL PROTECTED]; Java 1.5.0_10 #iters #elems For-each Indexed % Slower ------ ------ -------- ------- -------- 10^9 10^1 102.7s 73.6s 40% 10^8 10^2 107.8s 60.0s 80% 10^6 10^4 105.2s 58.6s 80% 10^4 10^6 58.8s 53.0s 11% 10^3 10^7 60.0s 54.1s 11% ----- ForEachTest.java follows ----- import java.util.Date; import java.util.Random; /** * This is meant to be called from a shell script that varies the loop style, * the number of iterations over the loop, and the number of elements in the * array over which the loop iterates, e.g.: * * cmd="java -server -cp . ForEachTest" * for elems in 10 100 10000 1000000 10000000 ; do * iters=$((10000000000/${elems})) * for run in 1 2 3 4 5 ; do * time $cmd --indexed --arraysize $elems --iterations $iters * time $cmd --foreach --arraysize $elems --iterations $iters * done * done * */ public class ForEachTest { static String NL = System.getProperty("line.separator"); static String usage = "Usage: java -server -cp . ForEachTest [ --indexed | --foreach ]" + NL + "\t--iterations <num-iterations> --arraysize <array-size>"; public static void main(String[] args) { boolean useIndexedLoop = false; int size = 0; int iterations = 0; try { for (int argnum = 0 ; argnum < args.length ; ++argnum) { if (args[argnum].equals("--indexed")) { useIndexedLoop = true; } else if (args[argnum].equals("--foreach")) { useIndexedLoop = false; } else if (args[argnum].equals("--iterations")) { iterations = Integer.parseInt(args[++argnum]); } else if (args[argnum].equals("--arraysize")) { size = Integer.parseInt(args[++argnum]); } else { throw new Exception("Unknown cmdline parameter '" + args[argnum] + "'."); } } } catch (Exception e) { System.err.println("Error parsing command line: " + e + NL); System.err.println(usage); System.exit(1); } // Initial the array with random integers int[] array = new int[size]; Random random = new Random(); for (int i = 0 ; i < size ; ++i) { array[i] = random.nextInt(); } int k = 0; if (useIndexedLoop) { System.out.println("Indexed : " + iterations + " iterations : " + size + " elements"); for (int m = 0 ; m < iterations ; ++m) { for (int j = 0 ; j < size ; ++j) { k = array[j]; } } } else { // useIndexedLoop = false System.out.println("For-each : " + iterations + " iterations : " + size + " elements"); for (int m = 0 ; m < iterations ; ++m) { for (int j : array) { k = j; } } } k = 0; } } --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]