Skip to content
HopperHopper

Course navigation

Unit 4 · Data CollectionsTopic 4.4

Array Traversals

  • About 60 minutes
  • 7 sections
  • Runnable Java examples
  • Practice questions

Before you start

About 60 minutes

By the end you will be able to

  1. Use a for loop and the length of an array to visit every element by its index, and avoid going one step past the end.
  2. Traverse part of an array, traverse it backward, or skip elements by changing the loop's start, test, and update.
  3. Traverse an array with a while loop that uses an index variable.
  4. Read and trace an enhanced for loop, and explain what its loop variable holds on each pass.
  5. Explain why assigning to the enhanced for loop variable never changes the array, while calling a mutator on it can change an object in the array.
  6. Rewrite an enhanced for loop as an indexed for loop or a while loop, and choose the right kind of loop for a task.
Section 1 of 7

4.4.1 Visiting Every Element with a for Loop

A weather app stores a week of daily high temperatures in an array. To show them, it has to print every one. With four temperatures you could write temps[0], temps[1], temps[2], and temps[3] on four lines, but a year of temperatures would need 365 nearly identical lines, and the code would break the moment the array had a different length.

Look at what changes from one of those lines to the next: only the index, which goes 0, 1, 2, 3. From Topic 2.8 you know a for loop is built for exactly that, a counter that starts somewhere, grows by 1, and stops at a limit. If the counter is used as the index, one loop body can reach every element in turn.

Using a loop to reach the elements of an array one after another is called traversing the array, and one complete run through it is a traversal. A traversal can visit every element, or only some of them in a planned order (that is 4.4.2). When the loop counter is the index, as here, the loop is called an indexed loop.

The standard header for visiting every element of an array named temps is:

for (int i = 0; i < temps.length; i++)
Piece What it does Why it is written this way
int i = 0 Starts the index at the first element The first index of every array is 0 (Topic 4.3)
i < temps.length Keeps looping while i is a valid index The last valid index is temps.length - 1, so i must stay less than the length
i++ Moves to the next index Neighboring elements have indexes that differ by 1
temps[i] in body Reads (or changes) the element at the current index The body works on one element per pass

Because the test uses temps.length instead of a typed number like 4, the same loop works for an array of any length.

Key idea

An indexed loop reaches each element through its index. To visit every element, start at 0, continue while the index is less than the array’s length, and add 1 each pass.

Worked example: Printing every temperature

Watch how i does two jobs: it picks the element, and it is also printed as the day number.

int[] temps = {68, 71, 75, 70};
for (int i = 0; i < temps.length; i++)
{
    System.out.println("Day " + i + ": " + temps[i]);
}

temps.length is 4, so the test on line 2 is i < 4.

i i < 4? temps[i] Printed
0 true 68 Day 0: 68
1 true 71 Day 1: 71
2 true 75 Day 2: 75
3 true 70 Day 3: 70
4 false (loop ends)

The body ran 4 times, once per element. When i became 4 the test was false, so temps[4], which does not exist, was never touched.

Day 0: 68
Day 1: 71
Day 2: 75
Day 3: 70

An indexed loop can also change elements, because points[i] on the left of = stores into the array (Topic 4.3). This program doubles every score, then uses a second traversal to print them.

int[] points = {3, 5, 8};
for (int i = 0; i < points.length; i++)
{
    points[i] = points[i] * 2;
}
for (int i = 0; i < points.length; i++)
{
    System.out.println(points[i]);
}

On line 4, the right side reads the current element and the = stores the doubled value back into the same slot. After the first loop the array holds {6, 10, 16}, and the second loop prints:

6
10
16

Remember this example; 4.4.5 shows a different loop that looks like it does the same thing but does not.

Watch out

Using <= instead of <. Students often think “the loop should go up to the length,” and write this:

int[] temps = {68, 71, 75, 70};
for (int i = 0; i <= temps.length; i++)
{
    System.out.println(temps[i]);
}

The first four passes print all four temperatures. Then i becomes 4, the test 4 <= 4 is still true, and line 4 asks for temps[4]. The valid indexes are 0 through 3, so the program crashes. The console shows something like this (the wording can vary between Java versions):

68
71
75
70
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 4 out of bounds for length 4

This is an off by one error (Topic 2.7) that the compiler cannot catch, because the code is legal; it fails only when it runs. The fix is i < temps.length. If you prefer to think “up to the last index,” write i <= temps.length - 1, which means the same thing.

Pause and try

Question 1 · Tracing

Write the exact output.

String[] words = {"map", "tree", "go"};
for (int k = 0; k < words.length; k++)
{
    System.out.println(k + " " + words[k].length());
}
Check your reasoning
0 3
1 4
2 2

words.length is 3, so k takes the values 0, 1, and 2. Each pass prints the index, a space, and the length of the string at that index.

k words[k] words[k].length() Printed
0 "map" 3 0 3
1 "tree" 4 1 4
2 "go" 2 2 2

At k = 3, the test 3 < 3 is false and the loop ends. Notice the two kinds of length: words.length (no parentheses) is the array’s length, and words[k].length() (with parentheses) is a String method.

Reread 4.4.1 Visiting Every Element with a for Loop if your output differed.

Question 2 · Multiple choice

What happens with this program?

LengthParens.java
public class LengthParens
{
    public static void main(String[] args)
    {
        int[] scores = {90, 85, 77};
        for (int i = 0; i < scores.length(); i++)
        {
            System.out.println(scores[i]);
        }
    }
}
  1. It prints 90, 85, and 77
  2. It prints 90, 85, and 77, then crashes with an ArrayIndexOutOfBoundsException
  3. It does not compile, because length for an array is not a method
  4. It prints nothing, because the loop test is false at the start
Check your reasoning

C. An array’s length is reached as scores.length, with no parentheses (Topic 4.3). Writing scores.length() asks for a method that arrays do not have, so Java reports something like error: cannot find symbol with symbol: method length() for line 6.

  • A is wrong: it would be right with scores.length, but the program never gets to run.
  • B is wrong: that is what <= would cause, and this test uses <. A compile error stops everything before any output.
  • D is wrong: a program that does not compile never evaluates its loop test.

Students mix this up because String uses length() with parentheses. Arrays use length without them.

Reread 4.4.1 Visiting Every Element with a for Loop if you chose differently.

Section 2 of 7

4.4.2 Other Starting Points, Directions, and Steps

A bus app lists the stops on a route. Riders going the other way want the list from the last stop to the first. A coach wants to call every other runner in a lineup. A track timer wants every lap except the first and last. None of these visits the elements from index 0 to the end one at a time, yet each still visits elements in a planned order.

The indexed for loop from 4.4.1 handles all of them, because each of its three parts can change, just as they did in Topic 2.8. The rule that never changes is that every index the body uses must be between 0 and length - 1.

To do this Start Test Update
Visit every element, forward 0 i < arr.length i++
Visit every element, backward arr.length - 1 i >= 0 i--
Visit every other element 0 i < arr.length i += 2
Skip the first and last 1 i < arr.length - 1 i++

Key idea

Changing where an indexed loop starts, when it stops, and how it steps lets you visit part of an array, go backward, or skip elements, as long as every index used stays from 0 to length minus 1.

Worked example: Stops in reverse

The loop starts at the last index and counts down. Look at the start value and the test.

String[] stops = {"Elm", "Oak", "Pine", "Main"};
for (int i = stops.length - 1; i >= 0; i--)
{
    System.out.println(stops[i]);
}

stops.length is 4, so the loop starts at i = 3, the last valid index.

i i >= 0? stops[i]
3 true "Main"
2 true "Pine"
1 true "Oak"
0 true "Elm"
-1 false (loop ends)

The test is >= 0, not > 0, because index 0 holds a real element that must be printed.

Main
Pine
Oak
Elm

Now change only the update. With i += 2, the loop jumps two indexes at a time:

String[] lineup = {"Ana", "Ben", "Cy", "Dee", "Eli"};
for (int i = 0; i < lineup.length; i += 2)
{
    System.out.println(lineup[i]);
}

i takes the values 0, 2, and 4, then becomes 6, and 6 < 5 is false. The program prints:

Ana
Cy
Eli

The test i < lineup.length still protects the array. If the lineup had 4 names instead of 5, i would go 0, 2, then 4, and 4 < 4 would stop the loop before reaching a bad index.

Watch out

Starting a backward loop at length. It is easy to write the start as “the length” when counting down:

String[] stops = {"Elm", "Oak", "Pine", "Main"};
for (int i = stops.length; i >= 0; i--)
{
    System.out.println(stops[i]);
}

On the very first pass, i is 4 and line 4 asks for stops[4]. Nothing prints at all; the program crashes right away with an ArrayIndexOutOfBoundsException saying index 4 is out of bounds for length 4. The length counts the elements, but the last index is one less. Start at stops.length - 1.

Pause and try

Question 3 · Tracing

Write the exact output.

int[] codes = {4, 9, 2, 7, 5, 1, 8};
for (int i = codes.length - 1; i > 0; i -= 3)
{
    System.out.println(codes[i]);
}
Check your reasoning
8
7

codes.length is 7, so i starts at 6.

i i > 0? codes[i] Printed
6 true 8 8
3 true 7 7
0 false (loop ends)

The test is i > 0, so index 0 is not visited even though it is a valid index. That is fine here: the loop was written to stop before it.

Reread 4.4.2 Other Starting Points, Directions, and Steps if your output differed.

Question 4 · Multiple choice

laps holds six lap times. What does this code print?

int[] laps = {52, 49, 47, 48, 50, 55};
for (int i = 1; i < laps.length - 1; i++)
{
    System.out.println("Lap " + i + ": " + laps[i]);
}
  1. Lap 1: 49 through Lap 4: 50, four lines
  2. Lap 1: 49 through Lap 5: 55, five lines
  3. Lap 0: 52 through Lap 4: 50, five lines
  4. Lap 1: 49 through Lap 5: 55, then an ArrayIndexOutOfBoundsException
Check your reasoning

A. laps.length - 1 is 5, so the test is i < 5 and i takes the values 1, 2, 3, and 4. The loop skips index 0 (it starts at 1) and index 5 (the test stops before it), so it prints Lap 1: 49, Lap 2: 47, Lap 3: 48, and Lap 4: 50.

  • B is wrong: that would need the test i < laps.length. Subtracting 1 in the test removes the last element.
  • C is wrong: the loop starts at i = 1, not 0.
  • D is wrong: every index used, 1 through 4, is valid, so nothing crashes.

Reread 4.4.2 Other Starting Points, Directions, and Steps if you chose differently.

Section 3 of 7

4.4.3 Traversing with a while Loop

Every traversal so far has used a for loop. In Topic 2.8 you learned that any for loop can be written as a while loop with the same three parts placed on separate lines. The same is true for traversals, and sometimes a while loop reads more naturally, for example when the loop should also stop early for a reason other than reaching the end.

A while traversal is still an indexed traversal: you need your own index variable, declared before the loop, tested in the condition, used inside the brackets, and updated at the end of the body.

int i = 0;                  // start
while (i < temps.length)    // test
{
    // use temps[i]
    i++;                    // update
}

Key idea

A while loop traverses an array the same way an indexed for loop does: declare an index before the loop, test it against the length, use it in brackets, and update it at the end of the body.

Worked example: The temperature report as a while loop

This produces exactly the same output as PrintTemps in 4.4.1. Match each part to the for header.

int[] temps = {68, 71, 75, 70};
int i = 0;
while (i < temps.length)
{
    System.out.println("Day " + i + ": " + temps[i]);
    i++;
}
for header part Where it is in the while version
int i = 0 Line 2, before the loop
i < temps.length Line 3, the while condition
i++ Line 6, the last line of the body

The trace is the same as before: i goes 0, 1, 2, 3, the body prints one line each time, and when i reaches 4 the condition is false.

Day 0: 68
Day 1: 71
Day 2: 75
Day 3: 70

Now vary the condition. A to-do list ends with a marker "done", and anything after the marker should be ignored. The while condition can check both “still inside the array” and “not at the marker yet”:

String[] tasks = {"wash", "dry", "done", "fold"};
int i = 0;
while (i < tasks.length && !tasks[i].equals("done"))
{
    System.out.println(tasks[i]);
    i++;
}
System.out.println("Stopped at index " + i);
wash
dry
Stopped at index 2
i i < 4? tasks[i] !tasks[i].equals("done")? Loop runs?
0 true "wash" true yes
1 true "dry" true yes
2 true "done" false no

This traversal visits an ordered part of the array, from the start up to the marker. Because i is declared before the loop, it still exists afterward, so line 8 can report where the loop stopped.

The order of the two tests matters. If the array has no "done" at all, i eventually reaches the length. Then i < tasks.length is false, and by short-circuit evaluation (Topic 2.5) Java never evaluates tasks[i]. Swap the two tests and that protection disappears:

String[] tasks = {"wash", "dry"};
int i = 0;
while (!tasks[i].equals("done") && i < tasks.length)
{
    System.out.println(tasks[i]);
    i++;
}
System.out.println("Stopped at index " + i);

This prints wash and dry, then crashes with an ArrayIndexOutOfBoundsException for index 2, because when i is 2 Java evaluates tasks[2] first. With the tests in the original order, the same two-element array prints wash, dry, and Stopped at index 2.

Watch out

Forgetting the update. In a for loop the update sits in the header where it is hard to forget. In a while loop it is a separate statement at the bottom of the body:

int i = 0;
while (i < temps.length)
{
    System.out.println(temps[i]);
}

i stays 0 forever, so the condition is always true and the loop never ends; it keeps printing the first temperature until someone stops the program. Add i++; as the last statement of the body.

Pause and try

Question 5 · Tracing

Write the exact output.

int[] seats = {12, 15, 9, 20, 11};
int n = seats.length - 1;
while (n >= 0)
{
    System.out.println(seats[n]);
    n -= 2;
}
Check your reasoning
11
9
12

seats.length is 5, so n starts at 4, the last index.

n n >= 0? seats[n] Printed
4 true 11 11
2 true 9 9
0 true 12 12
-2 false (loop ends)

This is a backward, every-other traversal written as a while loop. The update n -= 2 is on line 6, inside the body.

Reread 4.4.3 Traversing with a while Loop if your output differed.

Question 6 · Short answer

In UntilDone, the condition is i < tasks.length && !tasks[i].equals("done"). Explain why the test i < tasks.length has to come first.

Check your reasoning

Model answer: When the array has no "done" marker, i eventually equals tasks.length, which is not a valid index. With i < tasks.length first, that test is false, and && short-circuits, so Java never evaluates tasks[i]. If the marker check came first, Java would evaluate tasks[i] with i equal to the length and throw an ArrayIndexOutOfBoundsException, as GuardOrderWrong did.

A complete answer mentions:

  • When i reaches the length, tasks[i] is out of bounds.
  • && skips its right side when the left side is false, so the bounds test protects the array access only if it is on the left.

Reread 4.4.3 Traversing with a while Loop if your answer differed.

Section 4 of 7

4.4.4 The Enhanced for Loop

Look back at PrintTemps without the day numbers. If all you want is each temperature, the index variable is just bookkeeping: you set it up, test it, add 1 to it, and use it in brackets, all to get at values you could describe simply as “each temperature in the array.” Java has a shorter loop for exactly that situation.

The enhanced for loop (sometimes called a for-each loop) visits every element of an array from first to last without any index. Its header names a variable, and on each pass that variable is given a copy of the next element.

for (int t : temps)

Read it aloud as “for each int t in temps.”

Piece What it is
int The variable’s type, which must match the type of the array’s elements
t The enhanced for loop variable; it holds a copy of one element during each pass
: Separates the variable from the array; read it as “in”
temps The array to traverse

Behind the scenes Java still walks through the indexes 0, 1, 2, and so on, but you never see them. That means three things the indexed loop could do are impossible here: the loop always starts at the first element, always moves forward one element at a time, and never tells you the current index.

Key idea

An enhanced for loop gives its loop variable a copy of each element in order, from first to last, with no index involved.

Worked example: Each temperature, no index

Compare this to PrintTemps: there is no i, no .length, and no brackets.

int[] temps = {68, 71, 75, 70};
for (int t : temps)
{
    System.out.println(t);
}
Pass t holds a copy of Printed
1 temps[0], 68 68
2 temps[1], 71 71
3 temps[2], 75 75
4 temps[3], 70 70

After the fourth element there are no more, so the loop ends on its own. An enhanced for loop cannot run past the end of the array, because it never uses an index you could get wrong.

68
71
75
70

The element type does not have to be int. For an array of String, the loop variable is a String, so you can call String methods on it:

String[] guests = {"Rosa", "Kenji", "Amara"};
for (String guest : guests)
{
    System.out.println(guest + " has " + guest.length() + " letters");
}
Rosa has 4 letters
Kenji has 5 letters
Amara has 5 letters

Each pass, guest refers to the next name, and guest.length() is that name’s number of letters.

Watch out

Treating the loop variable as an index. Students used to indexed loops sometimes write temps[t]:

int[] temps = {68, 71, 75, 70};
for (int t : temps)
{
    System.out.println(temps[t]);
}

On the first pass t is 68, a temperature, not a position, so line 4 asks for temps[68]. Nothing prints; the program crashes with an ArrayIndexOutOfBoundsException for index 68. In an enhanced for loop the variable already is the element. Print t itself.

Pause and try

Question 7 · Tracing

This array happens to hold only values that are also valid indexes. Write the exact output.

int[] nums = {2, 0, 3, 1};
for (int value : nums)
{
    System.out.println(nums[value]);
}
Check your reasoning
3
2
1
0

value holds each element in turn, and line 4 uses it as an index.

Pass value nums[value]
1 2 3
2 0 2
3 3 1
4 1 0

It does not crash only because every element is between 0 and 3. This is the same mistake as in the Watch Out: value is an element, not a position, so the program prints the wrong things even though it runs.

Reread 4.4.4 The Enhanced for Loop if your output differed.

Question 8 · Multiple choice

What happens with this program?

WrongVarType.java
public class WrongVarType
{
    public static void main(String[] args)
    {
        int[] temps = {68, 71, 75, 70};
        for (String t : temps)
        {
            System.out.println(t);
        }
    }
}
  1. It prints 68, 71, 75, and 70
  2. It does not compile, because the loop variable’s type does not match the array’s element type
  3. It compiles but crashes, because an int cannot be stored in a String while the program runs
  4. It does not compile, because an enhanced for loop cannot be used on an int array
Check your reasoning

B. The loop variable receives each element, and the elements of temps are int values. A String variable cannot hold an int, so Java reports something like error: incompatible types: int cannot be converted to String for line 6. The fix is for (int t : temps).

  • A is wrong: the program never runs.
  • C is wrong: Java checks the types when it compiles, so this is a compile error, not a runtime crash.
  • D is wrong: enhanced for loops work on arrays of any type, including int, as EnhancedTemps showed.

Reread 4.4.4 The Enhanced for Loop if you chose differently.

Section 5 of 7

4.4.5 Assigning to the Loop Variable

In 4.4.1, an indexed loop doubled every score with points[i] = points[i] * 2. The enhanced for loop is shorter, so it is tempting to write the same job as “for each p in points, set p to p * 2.” Does that change the array?

The key word in 4.4.4 was copy. On each pass the loop variable gets a copy of the element, the same way a parameter gets a copy of its argument (Topic 3.5). Changing the copy does not reach back to the original. Think of copying a phone number from a contact list onto a sticky note: if you scribble a new number on the note, the contact list does not change.

Key idea

Assigning a new value to the enhanced for loop variable changes only the variable. The value stored in the array stays the same.

Worked example: Doubling that does not stick

The first loop assigns to p. The second loop shows what the array actually holds.

int[] points = {3, 5, 8};
for (int p : points)
{
    p = p * 2;
    System.out.println("p is now " + p);
}
for (int p : points)
{
    System.out.println("array holds " + p);
}
Pass Copied into p p after line 4 points array
1 3 6 {3, 5, 8}
2 5 10 {3, 5, 8}
3 8 16 {3, 5, 8}

Line 4 really does double p, and line 5 proves it. But p is a separate variable that held a copy, so the array column never changes. The second loop starts fresh, copies the original values, and prints them.

p is now 6
p is now 10
p is now 16
array holds 3
array holds 5
array holds 8

The same thing happens with an array of String. Here the loop tries to make each name uppercase:

String[] guests = {"Rosa", "Kenji"};
for (String guest : guests)
{
    guest = guest.toUpperCase();
}
System.out.println(guests[0] + " " + guests[1]);
Rosa Kenji

guest.toUpperCase() builds a new string, "ROSA", and line 4 makes guest refer to it. The array element still refers to the original "Rosa". As with a String parameter in Topic 3.6, assigning to the variable moves only the variable.

Watch out

Using an enhanced for loop to change array elements. EnhancedAssign and ShoutNames compile and run with no error message, which makes the bug hard to spot: the array just quietly stays the same. To store new values in an array, you need the index, so use an indexed loop and assign to the element:

for (int i = 0; i < guests.length; i++)
{
    guests[i] = guests[i].toUpperCase();
}

With this loop in place of lines 2 to 5, the program prints ROSA KENJI. For the scores, DoublePoints in 4.4.1 is the correct version.

Pause and try

Question 9 · Tracing

Write the exact output.

int[] quiz = {7, 9, 6};
for (int q : quiz)
{
    q += 1;
    System.out.println(q);
}
System.out.println(quiz[0] + " " + quiz[1] + " " + quiz[2]);
Check your reasoning
8
10
7
7 9 6
Pass Copied into q q after q += 1 Printed
1 7 8 8
2 9 10 10
3 6 7 7

Inside the loop, q really is 1 larger, so lines 4 and 5 print 8, 10, and 7. But q += 1 changes only the copy. Line 7 reads the array itself, which still holds 7 9 6.

Reread 4.4.5 Assigning to the Loop Variable if your output differed.

Question 10 · Multiple choice

guests is a String array holding "Rosa" and "Kenji". After this loop runs, what does guests hold?

for (String g : guests)
{
    g = g + "!";
}
  1. "Rosa!" and "Kenji!"
  2. "Rosa" and "Kenji"
  3. "Rosa" and "Kenji!", because only the last assignment is kept
  4. Nothing; the loop does not compile because g cannot be assigned
Check your reasoning

B. Each pass, g gets a copy of the reference stored in the array. g + "!" builds a new string, and the assignment makes g refer to it. The array’s elements are never assigned, so they still refer to "Rosa" and "Kenji". This is the same behavior as ShoutNames.

  • A is wrong: that would require assigning to guests[i] in an indexed loop. Assigning to the loop variable does not store into the array.
  • C is wrong: no assignment reaches the array, including the last one.
  • D is wrong: the loop variable can be assigned; Java allows it. It just has no effect on the array.

Reread 4.4.5 Assigning to the Loop Variable if you chose differently.

Section 6 of 7

4.4.6 Enhanced for Loops and Objects

A game keeps its players in an array of Player objects. At the end of a round, every player earns a 5-point bonus. From 4.4.5 you might expect an enhanced for loop to be useless for this, since it only hands out copies. But what exactly is being copied when the elements are objects?

From Topic 3.6, a variable of a class type holds a reference, the address of an object. An array of Player holds references too. So when the enhanced for loop copies an element into its variable, it copies the address, not the object. The loop variable becomes an alias of the object the array element refers to, exactly like a parameter that receives an object. That leads to two different outcomes:

Statement in the loop body What it changes Does the array see it?
p.addPoints(5); The object that p and the element both refer to Yes: the element still refers to that same, now-changed object
p = new Player("Rookie", 0); Only p, which now refers to a different object No: the element still holds its original reference

In the sticky-note picture, the note now has a house address on it. Going to the house and painting the door changes the house that the array’s address also leads to. Writing a different address on the note changes only the note.

Key idea

When an array holds objects, calling a mutator on the enhanced for loop variable changes the object the element refers to. It never changes which object each element refers to.

The programs in this subsection use a small Player class with a name, a point total, two accessors, and the mutator addPoints. Java allows only one public class per file, so the helper class here leaves off public; in a real project each class gets its own file.

Worked example: A bonus for every player

Lines 1 to 26 are the Player class. Watch line 35, which calls a mutator through the loop variable.

TeamBonus.java
class Player
{
    private String name;
    private int points;

    public Player(String playerName, int startPoints)
    {
        name = playerName;
        points = startPoints;
    }

    public String getName()
    {
        return name;
    }

    public int getPoints()
    {
        return points;
    }

    public void addPoints(int amount)
    {
        points += amount;
    }
}

public class TeamBonus
{
    public static void main(String[] args)
    {
        Player[] team = {new Player("Ada", 10), new Player("Bo", 7)};
        for (Player p : team)
        {
            p.addPoints(5);
        }
        for (Player p : team)
        {
            System.out.println(p.getName() + " " + p.getPoints());
        }
    }
}

Line 32 builds two Player objects. Call their addresses A and B; team[0] holds A and team[1] holds B.

Pass p holds a copy of Line 35 does Ada’s object Bo’s object
1 address A adds 5 to the object at A 15 7
2 address B adds 5 to the object at B 15 12

The array still holds addresses A and B, unchanged, but the objects at those addresses have new point totals. The second loop reads them:

Ada 15
Bo 12

Now vary the body: instead of calling a mutator, assign a new object to p.

TeamReplace.java
class Player
{
    private String name;
    private int points;

    public Player(String playerName, int startPoints)
    {
        name = playerName;
        points = startPoints;
    }

    public String getName()
    {
        return name;
    }

    public int getPoints()
    {
        return points;
    }

    public void addPoints(int amount)
    {
        points += amount;
    }
}

public class TeamReplace
{
    public static void main(String[] args)
    {
        Player[] team = {new Player("Ada", 10), new Player("Bo", 7)};
        for (Player p : team)
        {
            p = new Player("Rookie", 0);
        }
        for (Player p : team)
        {
            System.out.println(p.getName() + " " + p.getPoints());
        }
    }
}
Ada 10
Bo 7

Each pass, line 35 builds a new rookie and moves p to it. That changes only p. team[0] and team[1] still hold addresses A and B, and nothing changed those objects, so Ada and Bo keep their original points. The two rookies are lost when the loop moves on, because nothing holds their addresses.

Watch out

Expecting the enhanced for loop to replace objects in the array. To put a different object into each slot, you have to assign to the element itself, which needs an index:

for (int i = 0; i < team.length; i++)
{
    team[i] = new Player("Rookie", 0);
}

With this loop in place of lines 33 to 36, the program prints Rookie 0 twice. Use the enhanced for loop to use or update each object; use an indexed loop to replace elements.

Pause and try

Question 11 · Tracing

Write the exact output. (Player is the same class as in TeamBonus.)

MixedLoop.java
class Player
{
    private String name;
    private int points;

    public Player(String playerName, int startPoints)
    {
        name = playerName;
        points = startPoints;
    }

    public String getName()
    {
        return name;
    }

    public int getPoints()
    {
        return points;
    }

    public void addPoints(int amount)
    {
        points += amount;
    }
}

public class MixedLoop
{
    public static void main(String[] args)
    {
        Player[] team = {new Player("Kai", 4), new Player("Lee", 6)};
        for (Player p : team)
        {
            p.addPoints(2);
            p = new Player("Temp", 100);
            p.addPoints(2);
        }
        System.out.println(team[0].getName() + " " + team[0].getPoints());
        System.out.println(team[1].getName() + " " + team[1].getPoints());
    }
}
Check your reasoning
Kai 6
Lee 8

team[0] holds address A (Kai, 4) and team[1] holds address B (Lee, 6).

Pass Line p refers to Kai Lee Temp object
1 35 A (Kai) 6 6
1 36 new Temp object 6 6 100
1 37 Temp object 6 6 102
2 35 B (Lee) 6 8
2 36 new Temp object 6 8 100
2 37 Temp object 6 8 102

Line 35 runs while p is still an alias of the array’s object, so Kai and Lee each gain 2. Line 36 moves p to a brand-new object, so line 37 adds to that object instead. The array’s references never change, so lines 39 and 40 print Kai with 6 and Lee with 8.

Reread 4.4.6 Enhanced for Loops and Objects if your output differed.

Section 7 of 7

4.4.7 Choosing and Rewriting a Traversal

You now have three ways to traverse an array: an indexed for loop, a while loop, and an enhanced for loop. How do you choose? And if a program uses one kind, can you always switch to another?

Switching from an enhanced for loop to an indexed loop always works. The enhanced loop visits every element from first to last, and an indexed loop from 0 while i < arr.length does exactly the same. The trick is to recreate the loop variable: inside the body, wherever the enhanced loop used its variable, use arr[i]. The easiest way is to declare a variable with the same name and set it to arr[i] as the first line of the body; then the rest of the body does not change at all.

Key idea

Any enhanced for loop over an array can be rewritten as an indexed for loop or a while loop that visits indexes 0 through length minus 1 and uses arr[i] wherever the loop variable appeared.

Worked example: One traversal, three ways

All three loops print every color in order. Notice line 10 and line 18, which recreate c so the print statements stay the same.

String[] colors = {"red", "teal", "gold"};

for (String c : colors)
{
    System.out.println("enhanced: " + c);
}

for (int i = 0; i < colors.length; i++)
{
    String c = colors[i];
    System.out.println("indexed: " + c);
}

int j = 0;
while (j < colors.length)
{
    String c = colors[j];
    System.out.println("while: " + c);
    j++;
}
Loop Where c comes from Lines
Enhanced The loop gives c a copy of each element 3–6
Indexed String c = colors[i]; copies element i 8–12
while String c = colors[j]; copies element j 14–20

Each c inside a loop body is a separate local variable that exists only during its own loop, so reusing the name is allowed.

enhanced: red
enhanced: teal
enhanced: gold
indexed: red
indexed: teal
indexed: gold
while: red
while: teal
while: gold

The other direction does not always work. An enhanced for loop cannot replace an indexed loop that needs the index. Use this to choose:

The task needs to… Use Why
Read or use every element, first to last Enhanced for (simplest) No index to get wrong
Know the position (for example, print “Day 2”) Indexed for or while The enhanced loop never reveals the index
Store new values or new objects in the array Indexed for or while Only arr[i] = … changes an element
Go backward, skip elements, or visit only part Indexed for or while The enhanced loop always goes forward through all
Stop when a condition is met before the end while with two tests The condition can check the index and the value

Calling a mutator on objects in the array works with any of the three, as 4.4.6 showed.

Watch out

Rewriting with the index instead of the element. A student rewrites for (int age : ages) { System.out.println(age); } as an indexed loop but prints the counter:

int[] ages = {15, 17, 16};
for (int i = 0; i < ages.length; i++)
{
    System.out.println(i);
}
0
1
2

It prints the positions 0, 1, and 2 instead of the ages 15, 17, and 16. In an indexed loop, i is a position; the element is ages[i]. Printing ages[i] fixes it.

Pause and try

Question 12 · Short answer

For each task on an array prices, say whether an enhanced for loop can do it, and explain why or why not.

  1. Print every price, first to last.
  2. Add 1 to every price stored in the array.
  3. Print the prices from last to first.
Check your reasoning

Model answer:

  1. Yes. It only needs each element in order, which is exactly what an enhanced for loop provides.
  2. No. The loop variable holds a copy of each price, so assigning to it does not change the array. Storing a new value needs prices[i] = prices[i] + 1 in an indexed loop.
  3. No. An enhanced for loop always goes from the first element to the last. Going backward needs an indexed loop that starts at prices.length - 1 and counts down.

A complete answer gives a reason for each: the enhanced loop works on copies, always goes forward through every element, and has no index.

Reread 4.4.7 Choosing and Rewriting a Traversal if your answer differed.

Question 13 · Debugging

RewriteWrong was supposed to print the ages 15, 17, and 16 but printed 0, 1, and 2. Correct line 4, and explain the error.

Check your reasoning

Corrected line 4:

    System.out.println(ages[i]);

The loop counter i holds a position (0, 1, 2), not an element. In the enhanced loop, the variable age was the element itself; in the indexed version, the element at position i is ages[i]. With the fix, the program prints 15, 17, and 16. The original compiled and ran without any error, because printing an int counter is legal; it just printed the wrong values.

Reread 4.4.7 Choosing and Rewriting a Traversal if your fix differed.

Wrap-up · 1 of 5

Putting it together

This program uses every kind of traversal from the chapter on one array of Player objects (the same Player class as in 4.4.6). Before reading the explanation, predict the output.

RosterDay.java
class Player
{
    private String name;
    private int points;

    public Player(String playerName, int startPoints)
    {
        name = playerName;
        points = startPoints;
    }

    public String getName()
    {
        return name;
    }

    public int getPoints()
    {
        return points;
    }

    public void addPoints(int amount)
    {
        points += amount;
    }
}

public class RosterDay
{
    public static void main(String[] args)
    {
        Player[] roster = {new Player("Ada", 12), new Player("Bo", 9), new Player("Cy", 15)};

        for (Player p : roster)
        {
            p.addPoints(3);
        }

        roster[1] = new Player("Dee", 0);

        for (int i = 0; i < roster.length; i++)
        {
            System.out.println((i + 1) + ". " + roster[i].getName() + " " + roster[i].getPoints());
        }

        int k = roster.length - 1;
        while (k >= 0)
        {
            System.out.println(roster[k].getName());
            k--;
        }
    }
}

Call the three original objects A (Ada, 12), B (Bo, 9), and C (Cy, 15).

Lines What happens roster holds Points
32 An initializer list builds the array A, B, C 12, 9, 15
34–37 Enhanced for: p is an alias of each object in turn, and the mutator adds 3 to each A, B, C 15, 12, 18
39 Assigning to an element replaces Bo’s reference with a new object D (Dee, 0) A, D, C 15, 0, 18
41–44 Indexed for: i goes 0, 1, 2; the index is needed to print the place numbers i + 1 A, D, C 15, 0, 18
46–51 while loop, backward: k goes 2, 1, 0, printing names from last to first; at k = -1 the condition is false A, D, C 15, 0, 18
1. Ada 15
2. Dee 0
3. Cy 18
Cy
Dee
Ada

Each loop was chosen for its job. The bonus only needed each object, so the enhanced for loop was simplest; it worked because addPoints changes the objects, not the array. Replacing Bo needed an assignment to roster[1]. The numbered list needed the index, and printing in reverse needed an index that counts down. Bo’s object, now with 12 points, is lost because no element refers to it anymore.

Wrap-up · 2 of 5

Vocabulary

Term Definition Example
traversing (an array) Using a loop to reach the elements of an array one after another, either all of them or a planned part Printing every temperature
traversal One complete run of a loop through an array’s elements A backward pass over stops
indexed loop A for or while loop whose counter is used as the index to reach each element for (int i = 0; i < a.length; i++)
enhanced for loop A loop that visits every element of an array from first to last without an index for (int t : temps)
enhanced for loop variable The variable in an enhanced for loop’s header, which holds a copy of one element on each pass t in for (int t : temps)
ArrayIndexOutOfBoundsException (review) The runtime error caused by using an index below 0 or at least the array’s length temps[4] when the length is 4
Wrap-up · 3 of 5

Chapter summary

  • Traversing an array means using a loop to reach its elements in order, either all of them or a planned part.
  • An indexed for or while loop reaches elements through their indexes. To visit every element, go from 0 while the index is less than the length; any other start, test, or update is fine as long as every index stays between 0 and length minus 1, or the program throws an ArrayIndexOutOfBoundsException.
  • An enhanced for loop gives its variable a copy of each element, first to last, with no index. Assigning to that variable never changes the array.
  • When the elements are object references, the enhanced for loop variable is an alias of each object, so calling a mutator on it changes the object, but the references stored in the array stay the same.
  • Any enhanced for loop can be rewritten as an indexed for or while loop using arr[i]; tasks that need positions, a different order, or changes to the elements themselves require an indexed loop.
Wrap-up · 4 of 5

Review questions

Question 14 · Tracing

Write the exact output.

int[] vals = {1, 2, 3, 4, 5, 6};
for (int i = 1; i < vals.length; i += 2)
{
    vals[i] = vals[i] * 10;
}
for (int v : vals)
{
    v = 0;
}
for (int v : vals)
{
    System.out.println(v);
}
Check your reasoning
1
20
3
40
5
60

The first loop starts at index 1 and steps by 2, so i takes the values 1, 3, and 5 (then 7, and 7 < 6 is false). It multiplies only those elements by 10:

i Before After
1 2 20
3 4 40
5 6 60

The array is now {1, 20, 3, 40, 5, 60}. The second loop assigns 0 to its loop variable, which is only a copy, so the array does not change. The third loop prints each element.

Reread 4.4.2 Other Starting Points, Directions, and Steps and 4.4.5 Assigning to the Loop Variable if your output differed.

Question 15 · Multiple choice

Player is the same class as in TeamBonus. What happens when this program runs?

NullTeam.java
class Player
{
    private String name;
    private int points;

    public Player(String playerName, int startPoints)
    {
        name = playerName;
        points = startPoints;
    }

    public String getName()
    {
        return name;
    }

    public int getPoints()
    {
        return points;
    }

    public void addPoints(int amount)
    {
        points += amount;
    }
}

public class NullTeam
{
    public static void main(String[] args)
    {
        Player[] team = new Player[3];
        team[0] = new Player("Ada", 10);
        for (Player p : team)
        {
            p.addPoints(1);
            System.out.println(p.getName() + " " + p.getPoints());
        }
    }
}
  1. It prints Ada 11 and nothing else, because the loop skips empty elements
  2. It prints Ada 11, then crashes with a NullPointerException
  3. It prints Ada 11, null 1, and null 1
  4. It crashes before printing anything, with an ArrayIndexOutOfBoundsException
Check your reasoning

B. new Player[3] makes an array of three elements, each starting as null (Topic 4.3). Line 33 fills only team[0]. On the first pass, p refers to Ada, so line 36 adds 1 and line 37 prints Ada 11. On the second pass, p is a copy of team[1], which is null, and calling p.addPoints(1) on null throws a NullPointerException (Topic 1.14). The message looks something like java.lang.NullPointerException: Cannot invoke "Player.addPoints(int)"…, and its wording can vary between Java versions.

  • A is wrong: an enhanced for loop visits every element, including null ones. It does not check for them.
  • C is wrong: null is not an object, so there is no name or point total to print. Calling a method on it crashes.
  • D is wrong: the enhanced for loop never uses an index outside the array, and the crash happens on the second pass, after Ada was printed.

Reread 4.4.6 Enhanced for Loops and Objects if you chose differently.

Question 16 · Debugging

resetAll is supposed to set every team’s score back to 0, but the program prints 4 0 7. Explain the error and write corrected code for lines 17 to 20.

ScoreboardReset.java
class Scoreboard
{
    private int[] scores;

    public Scoreboard(int teams)
    {
        scores = new int[teams];
    }

    public void addScore(int team, int amount)
    {
        scores[team] += amount;
    }

    public void resetAll()
    {
        for (int s : scores)
        {
            s = 0;
        }
    }

    public int getScore(int team)
    {
        return scores[team];
    }
}

public class ScoreboardReset
{
    public static void main(String[] args)
    {
        Scoreboard board = new Scoreboard(3);
        board.addScore(0, 4);
        board.addScore(2, 7);
        board.resetAll();
        System.out.println(board.getScore(0) + " " + board.getScore(1) + " " + board.getScore(2));
    }
}
Check your reasoning

On each pass, s receives a copy of one element of the scores array. Line 19 sets that copy to 0, but the array’s elements are never assigned, so the scores stay 4, 0, and 7. The code compiles and runs without any error message, which is why the bug is easy to miss.

Corrected lines 17 to 20:

for (int i = 0; i < scores.length; i++)
{
    scores[i] = 0;
}

Assigning to scores[i] stores into the array itself. With this change the program prints 0 0 0. The fact that scores is a private instance variable does not matter here; resetAll is inside Scoreboard, so it may use the array either way.

Reread 4.4.5 Assigning to the Loop Variable if your fix differed.

Question 17 · Short answer

TeamBonus used an enhanced for loop to change every player’s points, but ShoutNames could not use one to change every guest’s name. Both arrays hold references. Explain why one works and the other does not.

Check your reasoning

Model answer: In both loops, the loop variable gets a copy of a reference, so it refers to the same object as the array element. In TeamBonus, p.addPoints(5) is a mutator: it goes to the shared Player object and changes it, so the array’s elements, which refer to the same objects, see the new points. A String has no mutators, because strings are immutable, so ShoutNames could only build a new string with toUpperCase() and assign it to guest. Assigning to the loop variable changes only that variable, never the reference stored in the array.

A complete answer includes:

  • Both loop variables are aliases of the objects in the array.
  • Calling a mutator changes the shared object; assigning to the loop variable does not change the array.
  • Strings are immutable, so the only option for a String is assignment, which does not stick.

Reread 4.4.5 Assigning to the Loop Variable and 4.4.6 Enhanced for Loops and Objects if your answer differed.

Question 18 · Multiple choice

Which while loop produces exactly the same output as this enhanced for loop?

double[] prices = {2.5, 4.0, 1.25};
for (double price : prices)
{
    System.out.println(price);
}
  1. int i = 0; while (i < prices.length) { System.out.println(prices[i]); i++; }
  2. int i = 0; while (i < prices.length) { i++; System.out.println(prices[i]); }
  3. int i = 0; while (i <= prices.length - 1) { System.out.println(prices[i]); }
  4. int i = prices.length; while (i > 0) { System.out.println(prices[i - 1]); i--; }
Check your reasoning

A. The enhanced loop prints 2.5, 4.0, and 1.25, every element from first to last. Choice A starts at 0, continues while i is a valid index, prints prices[i], and moves to the next index, so it prints the same three lines in the same order.

  • B is wrong: the update happens before the print, so the first element is skipped. It prints 4.0 and 1.25, then, when i becomes 3 inside the body, prices[3] throws an ArrayIndexOutOfBoundsException.
  • C is wrong: its test is fine (<= prices.length - 1 means the same as < prices.length), but it never updates i, so i stays 0 and the loop never ends.
  • D is wrong: it visits every element safely, but backward, printing 1.25, 4.0, 2.5. An enhanced for loop always goes first to last, so the order does not match.

Reread 4.4.3 Traversing with a while Loop and 4.4.7 Choosing and Rewriting a Traversal if you chose differently.

Question 19 · Tracing

A sensor records readings until it sends -1 to say it has stopped. Write the exact output.

int[] readings = {5, 8, -1, 4};
int i = 0;
while (i < readings.length && readings[i] >= 0)
{
    System.out.println(readings[i] * 2);
    i++;
}
System.out.println("i = " + i);
Check your reasoning
10
16
i = 2
i i < 4? readings[i] readings[i] >= 0? Printed
0 true 5 true 10
1 true 8 true 16
2 true -1 false (loop ends)

The loop stops at the first negative reading, so the 4 after it is never visited. i still exists after the loop because it was declared before it, and line 8 prints i = 2.

Reread 4.4.3 Traversing with a while Loop if your output differed.

Question 20 · Multiple choice

data has length 7. How many times does the body of this loop run, and which indexes does it visit?

int[] data = {10, 20, 30, 40, 50, 60, 70};
for (int i = data.length - 2; i >= 1; i -= 2)
{
    System.out.println(i + ": " + data[i]);
}
  1. 3 times: indexes 5, 3, and 1
  2. 4 times: indexes 6, 4, 2, and 0
  3. 3 times: indexes 6, 4, and 2
  4. 4 times: indexes 5, 3, 1, and then -1, which crashes
Check your reasoning

A. data.length - 2 is 5, so i starts at 5. It then becomes 3 and 1, and each of those passes the test i >= 1. The next value, -1, fails the test, so the loop ends after 3 passes. The program prints 5: 60, 3: 40, and 1: 20.

  • B is wrong: that would need a start of data.length - 1 and a test of i >= 0.
  • C is wrong: the start is data.length - 2, which is 5, not 6.
  • D is wrong: the test is checked before each pass, and -1 >= 1 is false, so the body never runs with i = -1.

Reread 4.4.2 Other Starting Points, Directions, and Steps if you chose differently.

Wrap-up · 5 of 5

Reflection

  • I can write the header of an indexed for loop that visits every element, and explain why the test uses less than the length. Reread
  • I can trace a traversal that goes backward, skips elements, or visits only part of an array. Reread
  • I can traverse an array with a while loop and explain why the bounds test comes first in a two-part condition. Reread
  • I can read an enhanced for loop and say what its variable holds on each pass. Reread
  • I can explain why assigning to the enhanced for loop variable does not change the array. Reread
  • I can predict whether a change made through the loop variable shows up in an array of objects. Reread
  • I can rewrite an enhanced for loop as an indexed loop and choose the right loop for a task. Reread