Most runtime in programs is spent in loops. The Java for
-loop iterates over numbers. Commonly used, this loop is ideal when processing known ranges.
In Java, no foreach
keyword is used. Instead we use the for
-keyword to iterate over each element in a collection. We do not need an index to do this.
This program uses a simple for
-loop. It declares the iteration variable "i" inside the condition of the loop. It starts at 0, and continues until it is equal to 5.
for
-loop condition is where the loop iteration variable is declared and initialized.for
-loop is the iteration statement. This is applied after each pass through the loop.public class Program { public static void main(String[] args) { // Part 1: start at 0. // Part 2: continue until 5 is reached. // Part 3: increment by 1. for (int i = 0; i < 5; i++) { System.out.println(i); } } }0 1 2 3 4
Often we use decrementing for
-loops to iterate backwards. The "greater than or equal to" operator means we include zero in the loop body.
public class Program { public static void main(String[] args) { // Loop from 3 to 0, decrementing. for (int i = 3; i >= 0; i--) { System.out.println(i); } } }3 2 1 0
This is a simple syntax form. If we loop over a collection, we use a colon, not an index variable. This enumerates each element in the collection (array, ArrayList
).
public class Program { public static void main(String[] args) { String[] values = new String[3]; values[0] = "Dot"; values[1] = "Net"; values[2] = "Perls"; for (String value : values) { System.out.println(value); } } }Dot Net Perls
A for
-loop can be stopped at any time, based on any condition. We use the "break
" statement. It takes no arguments and terminates the nearest enclosing loop.
break
out of a nested loop. A flag boolean, or the use of methods, is needed.for
-loop example scans each element in the values array. It stops (breaks) when a negative one element is found.public class Program { public static void main(String[] args) { int[] values = { 1, 2, 3, -1 }; // ... Loop over array indexes, but break on negative one. for (int i = 0; i < values.length; i++) { if (values[i] == -1) { break; } System.out.println(values[i]); } } }1 2 3
This keyword stops the current loop iteration and moves to the next one. Further statements are not executed. In a loop with an iteration condition, the next iteration begins.
public class Program { public static void main(String[] args) { String[] values = { "cat", "bear", "dog", "bird" }; // Loop over all Strings. for (String value : values) { // Skip Strings starting with letter b. if (value.startsWith("b")) { continue; } System.out.println(value); } } }cat dog
for
-loopsAll kinds of loops can be nested. When we use a break
or continue statement with a nested loop, only the innermost loop is affected.
public class Program { public static void main(String[] args) { // Use nested for-loops. for (int i = 0; i < 3; i++) { for (int y = 0; y < 3; y++) { System.out.println(i + "," + y); } } } }0,0 0,1 0,2 1,0 1,1 1,2 2,0 2,1 2,2
Sometimes an iteration variable needs to be reused outside of a for
-loop. We can use any local variable in a new for
-loop.
public class Program { public static void main(String[] args) { int x = 0; // Parts of the for-loop can be omitted. // ... Here we use no variable declaration in the for-statement. for (; x < 3; x++) { System.out.println(x); } System.out.println("x is still reachable!"); System.out.println(x); } }0 1 2 x is still reachable! 3
for
-eachA method can be called in the for
-loop. This method is evaluated once and then the results of it are accessed in the loop iteration variable.
getElements
is only called once. It is not called three times.for
-each loop, we can see that the result is cached in a local and not evaluated more than once.public class Program { static int count; static int[] getElements() { // Set array elements based on a static field. int[] array = new int[3]; array[0] = count++; array[1] = count++; array[2] = count++; return array; } public static void main(String[] args) { // The method is called once and not many times in the for-loop. for (int value : getElements()) { System.out.println(value); } } }0 1 2
Loops in Java can wrap around. This can happen in loops where we increment or decrement. The int
type overflows and becomes negative, then reaches the target.
for
-each loop also helps.public class Program { public static void main(String[] args) { long iterations = 0; // Count iterations from 100 to 200 decrementing. for (int u = 100; u <= 200; u--) { iterations++; } System.out.println("Iterations from 100 to 200: " + iterations); } }Iterations from 100 to 200: 2147483749
String
loopThis program uses a for
-loop over a String
. We start at index 0 and process until the length()
is reached. With charAt
we get each character at an index.
public class Program { public static void main(String[] args) { String value = "art"; // Loop from 0 to length() of the string. for (int i = 0; i < value.length(); i++) { // Get letters with charAt method. char letter = value.charAt(i); System.out.println(letter); } } }a r t
In loop jamming many loops are combined into one. Consider this program—three arrays, all of the same length, must be looped over.
public class Program { public static void main(String[] args) { int[] array1 = { 10, 20, 30 }; int[] array2 = { 20, 10, 30 }; int[] array3 = { 40, 40, 10 }; long t1 = System.currentTimeMillis(); // Version 1: loop over each array separately. for (int i = 0; i < 10000000; i++) { int sum = 0; for (int x = 0; x < array1.length; x++) { sum += array1[x]; } for (int x = 0; x < array2.length; x++) { sum += array2[x]; } for (int x = 0; x < array3.length; x++) { sum += array3[x]; } if (sum != 210) { System.out.println(false); } } long t2 = System.currentTimeMillis(); // Version 2: jam loops together. for (int i = 0; i < 10000000; i++) { int sum = 0; for (int x = 0; x < array1.length; x++) { sum += array1[x]; sum += array2[x]; sum += array3[x]; } if (sum != 210) { System.out.println(false); } } long t3 = System.currentTimeMillis(); // ... Times. System.out.println(t2 - t1); System.out.println(t3 - t2); } }109 ms, 3 for-loops 48 ms, 1 for-loop (jammed)
Sometimes loops are unnecessary. In loop unrolling, we change a loop to a list of statements. We can loop over groups of statements at once.
public class Program { public static void main(String[] args) { int[] array1 = new int[5]; long t1 = System.currentTimeMillis(); // Version 1: assign elements in a loop. for (int i = 0; i < 10000000; i++) { for (int x = 0; x < array1.length; x++) { array1[x] = x; } } long t2 = System.currentTimeMillis(); // Version 2: unroll the loop and use a list of statements. for (int i = 0; i < 10000000; i++) { array1[0] = 0; array1[1] = 1; array1[2] = 2; array1[3] = 3; array1[4] = 4; } long t3 = System.currentTimeMillis(); // ... Times. System.out.println(t2 - t1); System.out.println(t3 - t2); } }56 ms, for-loop 17 ms, unrolled statements
Loops are key to optimizations. Often we eliminate steps from the loop body by changing the loop declaration. Loops affect control flow, causing it to repeat.