Room 4 of 15 · about 30 minutes

Walking every slot with a for loop

Room 3 gave you one slot at a time by hand. A loop does the same thing for every slot without you writing a line per slot.

Tasks checked0 of 4 XP earned on this path0

What this room checks you can do

Student can produce a traditional for loop header that visits every element of an array in order, using int i = 0, i < a.length, and i++, and explain which part of the loop body needs the index variable (versus only the value).

Notes

The classic for (int i = 0; i < a.length; i++) loop

The traditional counted for loop is the canonical way to walk every slot of an array in order. Its shape is fixed enough that an experienced reader recognizes it at a glance, and the recognition is the point.

for (int i = 0; i < xs.length; i++) {
    System.out.println(xs[i]);
}

The three parts of the header each play a specific role (JLS §14.14.1):

1. Initialization (int i = 0) declares the loop counter and sets it to the first valid index. The declaration is inside the header, so i exists only for the duration of the loop. 2. Condition (i < xs.length) runs before each iteration. The loop body runs while this expression is true. The strict <, which the loop-bound rule states, is what keeps i inside the valid index range. 3. Update (i++) runs after each iteration. The unary ++ increments the counter by one, which advances to the next slot.

When you need the index during the body (to look at the previous element, to access a parallel array, to print the slot number), this loop is the right tool. The enhanced-for loop, written for (int v : xs), gives you the value but hides the index.

Reading the loop as a contract

The loop body sees i taking every integer value from 0 to xs.length - 1, in that order, one value per iteration. Inside the body, xs[i] is the element at the current position, xs[i-1] is the previous (when defined), and xs[i+1] is the next (when defined). The loop guarantees the order; the body acts on each slot once.

When you want to start somewhere else

The header is parameterizable: int i = 1 skips the first element; i += 2 visits every other slot; i = xs.length - 1 paired with i >= 0 and i-- walks the array in reverse. The mental model is "I am the index: where am I starting, what stops me, how do I move?"

In other languages

  • C: identical shape: for (int i = 0; i < n; i++) { / ... / }. Java inherits the C for syntax verbatim.
  • Python: for i in range(len(xs)): is the analog; the more idiomatic form is for v in xs: (Java's enhanced-for, area 05). Python lacks the C-style three-part header.
  • JavaScript: identical to Java; for (let i = 0; i < arr.length; i++). Modern JS often uses for (const v of arr) instead.

i < a.length (strict less-than) is the right bound

The loop condition that visits every slot of xs and stops at exactly the right time is i < xs.length. Strict less-than. Not <=. The reason is the half-open interval convention that pervades Java's array model:

  • Valid indices: 0, 1, …, xs.length - 1
  • Equivalent interval notation: [0, xs.length) ← the right endpoint is excluded

Reading the condition i < xs.length as "while i is a valid index" makes the loop self-evident. Every iteration starts with i in range, runs the body once on xs[i], then increments, and the loop stops the first time i reaches xs.length, which is one past the last valid index.

final int[] xs = {10, 20, 30};        //  length 3, valid indices 0..2
for (int i = 0; i < xs.length; i++) { //  runs with i = 0, 1, 2
    System.out.println(xs[i]);        //  prints 10, 20, 30: done
}

The accidental swap to <= produces one extra iteration with i == xs.length, and xs[xs.length] is out of range: ArrayIndexOutOfBoundsException, which array access and length covers. Crucially, the exception fires at the end of the traversal, after every prior iteration succeeded. Debugging is harder because the visible symptom is "the loop crashed at the end," not "the loop has the wrong bound."

Why half-open

The half-open [0, length) convention has practical consequences worth noticing:

  • The number of iterations is length - 0 == length: easy mental math.
  • The loop is symmetric for any subrange: for (int i = a; i < b; i++) visits b - a elements.
  • Two adjacent ranges, [a, m) and [m, b), partition [a, b) without overlap or gap. (Used by binary search and the merge step of merge sort.)

Closed-interval conventions ([0, length]) lack all three properties. The half-open form is so universal in modern languages that even Python's range(n) produces 0, 1, …, n-1 for the same reason.

A safety net for null and empty

If xs is null, the access xs.length throws NullPointerException before the loop ever runs: the bug is at the array reference, not at the loop bound. If xs.length == 0, the condition 0 < 0 is immediately false; the loop body runs zero times and the program continues. Both behaviors are intentional and useful: the empty-array case is the reason return new int[0] is preferable to return null, which the rule for returning an array from a method states.

In other languages

  • C: identical: for (int i = 0; i < n; i++). C does not bounds-check, so the consequence of <= is a buffer overrun, not an exception.
  • Python: range(len(xs)) produces the half-open [0, len) automatically. The equivalent off-by-one error needs range(len(xs) + 1), which is harder to write accidentally.
  • Rust: for i in 0..xs.len() is the half-open form; 0..=xs.len() is the closed-interval form (almost always wrong for indexing). The syntax makes the choice explicit.

Tasks

Do each one, then check the box. Checking a box is you saying you did it. You can uncheck a box if you check it by accident.

  1. trace
    Show the answer

    18.

  2. trace
    Show the answer

    1, 3, 5.

  3. write
    Show the answer

    classic for loop header + System.out.println(xs[i]).

  4. write
    Show the answer

    for (int i = xs.length - 1; i >= 0; i--): note >= 0, not > 0, because index 0 is valid.

Self check

Type what you think the answer is. Getting it wrong costs nothing and you can try as many times as you want.

Given int[] xs = new int[0]; for (int i = 0; i < xs.length; i++) System.out.println("hi");, predict the output.

Practice, untimed

Open this whenever you want, before the tasks or after them. Nothing in this section is recorded and nothing here is timed.

  1. Given int[] xs = {1, 2, 3, 4}; for (int i = 0; i <= xs.length; i++) System.out.println(xs[i]);, predict the program's output and final state.trace
    Show the answer

    1, 2, 3, 4 printed, then ArrayIndexOutOfBoundsException: Index 4 out of bounds for length 4 at the next iteration.

  2. Write a loop that prints every other element of xs (indices 0, 2, 4, …) with the right bound.write
    Show the answer

    for (int i = 0; i < xs.length; i += 2).

  3. Produce a counted reverse-printing loop.write
    Show the answer

    for (int i = xs.length - 1; i >= 0; i--).

  4. Given int[] xs = null; for (int i = 0; i < xs.length; i++) System.out.println(xs[i]);, predict the runtime outcome.trace
    Show the answer

    NullPointerException on the evaluation of xs.length, before any iteration.

Optional challenge

This one is optional. Do what the room says you can do, without opening any answers, then read the two traps below and check your work against them. Each trap is copied from the notes for this room.

Student can produce a traditional for loop header that visits every element of an array in order, using int i = 0, i < a.length, and i++, and explain which part of the loop body needs the index variable (versus only the value).

How this room finishes

This room is done when all four tasks are checked and the self check is answered.