Skip to content
Study Hall
Lesson 2 of 5Arrays
Unit 6 · Lesson 2 of 5

Traversing Arrays and the Standard Algorithms

The two ways to walk an array, and the handful of algorithms — sum, average, max, count, search, reverse — that every array question is built from.

8 min read12 practice questionsAsk AI about this →

Key things to remember

  1. 1The standard traversal is for (int i = 0; i < arr.length; i++) — strict less-than, never <=.
  2. 2Use for-each when you need only the values; use the index loop when you must modify elements or report a position.
  3. 3Assigning to a for-each loop variable changes a copy and leaves the array unchanged.
  4. 4Initialize a max or min search with arr[0], never with 0, then loop from index 1.
  5. 5A linear search returns the index on a match and −1 after the loop if nothing matched.
  6. 6Swapping needs a temporary variable, and reversing swaps from both ends inwards for length / 2 passes.

An array on its own is just storage. It becomes useful the moment a loop walks it, because then one body of code processes every element no matter how many there are. Walking every element in order is called traversal, and the classic form counts an index from 0 up to but not including the length. Learn for (int i = 0; i < arr.length; i++) as one fixed phrase and type it as a unit: i = 0 starts at the first element, i < arr.length stops one past the last valid index, and i++ moves on by one slot.

int[] marks = {78, 92, 65, 88, 71};

for (int i = 0; i < marks.length; i++) {
    System.out.println("Mark " + i + " is " + marks[i]);
}
Five passes, i taking 0, 1, 2, 3, 4. The strict less-than is what keeps it in bounds.
A traversal visits every box once, in order, using the index as the counter.int[] a = {4, 8, 15, 16};for (int i = 0; i < a.length; i++) { System.out.println(a[i]);}4i = 08i = 115i = 216i = 3i walks from 0 up to length − 1ia[i]printed0441882151531616i = 4 → 4 < 4 is false → the loop stopsi is the index — which box youare at. a[i] is the element —what is inside that box.
Fig 1One index variable stepping through the slots, one element visited per pass.

When you only need the values and never the positions, Java offers a shorter form. Read for (int mark : marks) as "for each mark in marks". There is no counter to initialize, no condition to get wrong and no index to go out of bounds, so it removes a whole family of bugs at once — which is why you should reach for it by default. It cannot be used in two situations, though. The first is when you need the index itself, to report a position, to step backwards, or to visit only part of the array. The second is when you need to modify the elements: the loop variable receives a copy of each element, so assigning to it changes the copy and leaves the array untouched, with no warning from the compiler at all. To write into an array you need the index, and therefore the standard for loop.

int[] values = {1, 2, 3};

int total = 0;
for (int v : values) {
    total += v;              // reading is exactly what for-each is for
}
System.out.println(total);       // 6

for (int v : values) {
    v = v * 10;              // changes only the copy
}
System.out.println(values[0]);   // still 1 - nothing happened

for (int i = 0; i < values.length; i++) {
    values[i] = values[i] * 10;  // writes back into the array
}
System.out.println(values[0]);   // now 10

The accumulator pattern is the same as with any loop: declare the total before the loop, add inside it, use it after. The one trap is the average, because dividing two ints in Java throws away the fractional part. 394 / 5 gives 78, not 78.8. Casting one side to double fixes it, and the cast must happen before the division, not after — (double) total / n is right, while (double) (total / n) has already lost the decimals by the time the cast runs.

public class MarkStats {
    public static void main(String[] args) {
        int[] marks = {78, 92, 65, 88, 71};

        int total = 0;
        for (int mark : marks) {
            total += mark;
        }

        double average = (double) total / marks.length;

        System.out.println("Total:   " + total);     // 394
        System.out.println("Average: " + average);   // 78.8
    }
}
78 + 92 + 65 + 88 + 71 = 394, and 394 divided by 5 is 78.8.
Initialize from element zero, not from zero
To find a maximum, write int max = arr[0]; and then loop from index 1. Starting at 0 works only when every element is positive — feed it a week of winter temperatures and it will confidently report 0, a value that is not even in the array. Starting from the first element guarantees the running maximum is always a real member of the data. The same rule applies to the minimum.
int[] temps = {-5, -12, -3, -8};

int max = temps[0];
int min = temps[0];
for (int i = 1; i < temps.length; i++) {
    if (temps[i] > max) {
        max = temps[i];
    }
    if (temps[i] < min) {
        min = temps[i];
    }
}

System.out.println("High: " + max);   // -3
System.out.println("Low:  " + min);   // -12
Starting from element 0 handles all-negative data correctly. Starting from 0 would report 0.

Counting asks "how many", so it visits every element and increments a counter inside an if. Searching asks "where", so it can stop the instant it finds what it wants. The convention for a search that finds nothing is to return −1, because −1 is never a valid index and so can never be mistaken for a real answer. One warning about where that line goes: return -1; must be after the loop, not in an else inside it. Put it inside and the method reports failure after checking only the first element — the search has failed only once the whole loop has finished without returning.

public class Search {

    // How many marks are at least the cutoff?
    public static int countAtLeast(int[] arr, int cutoff) {
        int count = 0;
        for (int value : arr) {
            if (value >= cutoff) {
                count++;
            }
        }
        return count;
    }

    // Where is the target? Returns the index, or -1 if it is absent.
    public static int indexOf(int[] arr, int target) {
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == target) {
                return i;          // found it - stop immediately
            }
        }
        return -1;                 // only reached if the loop never matched
    }

    public static void main(String[] args) {
        int[] marks = {78, 92, 65, 88, 71};
        System.out.println(countAtLeast(marks, 80));   // 2
        System.out.println(indexOf(marks, 65));        // 2
        System.out.println(indexOf(marks, 50));        // -1
    }
}
Counting must see every element. Searching should stop at the first match.

Swapping two elements needs a third variable. Writing a[i] = a[j]; first destroys the old value of a[i] before anything has saved it, so both slots end up holding the same thing. Park one value in a temporary variable, and the swap is three safe lines: save, copy over, restore. Reversing an array is that same swap applied from both ends inwards, which is why the loop only runs to the halfway point — going all the way would swap every pair twice and put the array back exactly as it started.

int[] a = {1, 2, 3, 4, 5};

for (int i = 0; i < a.length / 2; i++) {
    int temp = a[i];                     // 1. save
    a[i] = a[a.length - 1 - i];          // 2. copy over
    a[a.length - 1 - i] = temp;          // 3. restore
}
// i = 0 swaps a[0] and a[4]  ->  5 2 3 4 1
// i = 1 swaps a[1] and a[3]  ->  5 4 3 2 1
// loop stops: 5 / 2 is 2, so i never reaches 2 and the middle stays put
Integer division makes the halfway bound work for odd and even lengths alike.

Real data has more than one field per thing: a student has a name and a mark, a product has a code and a price. Before you meet objects, the usual answer is parallel arrays — two or more arrays of the same length where index i in each refers to the same real-world item. Write String[] names = {"Aisha", "Ben", "Chloe"}; beside int[] marks = {88, 72, 95}; and one loop over the shared index prints names[i] + ": " + marks[i] for each person. The arrays are joined only by that shared index, and that is exactly what makes them fragile.

Parallel arrays: position i in one array belongs with position i in the other.String[] names = {"Ada", "Ben", "Cal", "Dia"};int[] scores = { 88, 74, 91, 65 };namesscoresAdaindex 088Benindex 174Calindex 291Diaindex 365Cal → 91Fragile: the only thing joining a name to a score is the index.Sort scores without moving names the same way and every pair is silently wrong — no error, just bad data.Keep the arrays the same length and change them together, or move to one array of objects later on.
Fig 2Two arrays, one shared index. Element 2 of each belongs to the same person.
Parallel arrays break quietly
Nothing in the language ties the arrays together. Sort one and not the other and every mark is now attached to the wrong name — with no error, no crash and output that still looks perfectly plausible. Insert into one and forget the other and the lengths drift apart. Whenever you change one array, you must make the identical change to all of them in the same step.

Worked examples

Reveal one step at a time and try to beat it to the next line.

Example 1
Given int[] data = {12, 5, 9, 20, 3}; hand-trace a loop that computes the total and the maximum, then state both results.
Example 2
Write a method countBelow(double[] temps, double limit) that returns how many readings are below the limit, and explain which loop you chose.
Example 3
A student's search always reports −1 even for values that are present. Their code is: for (int i = 0; i < arr.length; i++) { if (arr[i] == target) { return i; } else { return -1; } } Explain and fix it.
Example 4
Swap the first and last elements of int[] a = {7, 1, 4}; using a temporary variable, and show why the obvious two-line version fails.

Where marks get lost

  • Using i <= arr.length in the loop condition, which throws ArrayIndexOutOfBoundsException on the final pass.
  • Trying to modify elements inside a for-each loop — the loop variable is a copy, so the array never changes.
  • Starting a maximum search at 0 instead of arr[0], which reports 0 for all-negative data.
  • Putting return -1; inside the search loop, so failure is declared after checking only the first element.
  • Sorting or editing one parallel array and not the others, silently pairing every name with the wrong data.

Flashcards 9

Write the standard array traversal header.
When can a for-each loop NOT be used?
What should a max search be initialized to?
What does a linear search return when the target is absent?
+ 5 more

Practice

1
What is printed? int[] a = {4, 7, 2, 9}; int t = 0; for (int v : a) { t += v; } System.out.println(t);
2
Which task CANNOT be done with an enhanced for-each loop?
3
What should a maximum search be initialized to before the loop?
4
By convention, what value does a linear search return when the target is not in the array?
5
For int[] m = {55, 81, 90, 47, 80}; how many elements satisfy m[i] >= 80?
6
How many passes does for (int i = 1; i < arr.length; i++) make when arr has 6 elements?
passes
7
Order the three statements that correctly swap a[i] and a[j].
  1. 1a[i] = a[j];
  2. 2int temp = a[i];
  3. 3a[j] = temp;
8
Match each standard algorithm to the line at its core.
Sum
Count matches
Find the maximum
Linear search
9
Why does a reverse loop use the condition i < a.length / 2?
10
A program stores names in one array and marks in another. A sort is applied to the marks array only. What happens?
11
What is printed? int[] a = {1, 2, 3}; for (int v : a) { v = v * 10; } System.out.println(a[0]);
12
int[] a = {5, 10}; double avg = a[0] + a[1] / 2; gives 10.0 instead of 7.5. What is wrong?

Spot a mistake on this page? Let us know