4.8 The for(:) Statement
The enhanced for loop is convenient when we need to iterate over an array or a collection, especially when some operation needs to be performed on each element of the array or collection. In this section we discuss iterating over arrays. In §15.2, p. 795, we take a look at the for(:) loop for iterating over collections.
Earlier in this chapter we used a for(;;) loop to sum the values of elements in an int array:
int sum = 0;
int[] intArray = {12, 23, 5, 7, 19};
for (int index = 0; index < intArray.length; index++) { // (1) using for(;;) loop
sum += intArray[index];
}
The for(;;) loop at (1) is rewritten using the for(:) loop in Figure 4.9.
Figure 4.9 Enhanced for Statement
The body of the loop is executed for each element in the array, where the variable element successively denotes the current element in the array intArray. When the loop terminates, the variable sum will contain the sum of all elements in the array. We do not care about the position of the elements in the array, just that the loop iterates over all elements of the array.
From Figure 4.9 we see that the for(:) loop header has two parts. The expression must evaluate to a reference value that refers to an array (or an object which implements the Iterable<E> interface (§15.2, p. 791)). The array can be an array of primitive values or objects, or even an array of arrays. The expression is evaluated only once. The element declaration specifies a local variable that can be assigned a value of the element type of the array. The type of the array intArray in Figure 4.9 is int[], and the element type is int. The element variable of type int can be assigned int values from the array of int. However, this assignment might require either a boxing or an unboxing conversion, with optional widening conversion.
The element variable is local to the loop block and is not accessible after the loop terminates. Also, changing the value of the current variable does not change any value in the array. The loop body, which can be a simple statement or a statement block, is executed for each element in the array and there is no danger of any out-of-bounds errors.
The for(:) loop has its limitations. Specifically, we cannot change element values, and this kind of loop does not provide any provision for positional access using an index. The for(:) loop only increments by one and always in a forward direction. It does not allow iterations over several arrays simultaneously. Under such circumstances, the for(;;) loop can be more convenient.
Here are some code examples of legal for(:) loops:
// Some one-dim arrays:
int[] intArray = {10, 20, 30};
Integer[] intObjArray = {10, 20, 30};
String[] strArray = {“one”, “two”};
// Some two-dim arrays:
Object[][] objArrayOfArrays = {intObjArray, strArray};
Number[][] numArrayOfArrays = {{1.5, 2.5}, intObjArray, {100L, 200L}};
int[][] intArrayOfArrays = {{20}, intArray, {40}};
// Iterate over a String array.
// Expression type is String[], and element type is String.
// String is assignable to Object (widening conversion).
for (Object obj : strArray) {}
// Iterate over an int array.
// Expression type is int[], and element type is int.
// int is assignable to Integer (boxing conversion)
for (Integer iRef : intArrayOfArrays[0]){}
// Iterate over an Integer array.
// Expression type is Integer[], and element type is Integer.
// Integer is assignable to int (unboxing conversion)
for (int i : intObjArray){}
// Iterate over a two-dim int array.
// Outer loop: expression type is int[][], and element type is int[].
// Inner loop: expression type is int[], and element type is int.
for (int[] row : intArrayOfArrays)
for (int val : row) {}
// Iterate over a two-dim Number array.
// Outer loop: expression type is Number[][], and element type is Number[].
// Outer loop: Number[] is assignable to Object[] (widening conversion).
// Inner loop: expression type is Object[], and element type is Object.
for (Object[] row : numArrayOfArrays)
for (Object obj : row) {}
// Outer loop: expression type is Integer[][], and element type is Integer[].
// Outer loop: Integer[] is assignable to Number[].
// Inner loop: expression type is int[], and element type is int.
// Inner loop: int is assignable to double.
for (Number[] row : new Integer[][] {intObjArray, intObjArray, intObjArray})
for (double num : intArray) {}
Here are some code examples of for(:) loops that are not legal:
// Expression type is Number[][], and element type is Number[].
// Number[] is not assignable to Number.
for (Number num : numArrayOfArrays) {} // Compile-time error!
// Expression type is Number[], and element type is Number.
// Number is not assignable to int.
for (int row : numArrayOfArrays[0]) {} // Compile-time error!
// Outer loop: expression type is int[][], and element type is int[].
// int[] is not assignable to Integer[].
for (Integer[] row : intArrayOfArrays) // Compile-time error!
for (int val : row) {}
// Expression type is Object[][], and element type is Object[].
// Object[] is not assignable to Integer[].
for (Integer[] row : objArrayOfArrays) {} // Compile-time error!
// Outer loop: expression type is String[], and element type is String.
// Inner loop: expression type is String, which is not legal here. Not an array.
for (String str : strArray)
for (char val : str) {} // Compile-time error!
When using the for(:) loop to iterate over an array, the two main causes of errors are an expression in the loop header that does not represent an array and/or an element type of the array that is not assignable to the local variable declared in the loop header.