Skip to content
Ameen Abozaid
PublishedBEG-015-L02

Iterating and enhanced for

  • Lesson 2 of 8
  • 11 min read
  • Beginner
On This Lesson 11 topics

Lesson Overview

An array is only useful if you can visit its elements. In Lesson 1 you wrote one loop for that. This lesson makes the pattern automatic and adds a second, simpler loop for the common case where you only need the values.

Back to the lockers. There are two ways to inspect a row of lockers. You can walk along with a numbered clipboard, saying "locker 0, locker 1, locker 2..." (the classic for loop). Or you can let an assistant hand you each item in turn without telling you the number (the enhanced for loop). The clipboard gives you control; the assistant gives you simplicity.

Why this matters: summing an order, finding the cheapest item, checking that every field is filled: all backend list processing is some form of "visit each element". The most common array bug, the off-by-one index, lives in exactly this loop, so we also practise the habit that prevents it.

This lesson builds on arrays (Lesson 1) and the for loop and off-by-one errors (BEG-013).

Learning Objectives

By the end of this lesson you will be able to:

  • Write the classic indexed loop over an array with the correct bounds.
  • Write an enhanced for loop and say what it gives you.
  • Choose between the two loops for a given task.
  • Explain why assigning to the enhanced-for variable does not change the array.
  • Loop backwards and over part of an array.
  • Check, before running, that every index in a loop stays between 0 and length - 1.
  • Handle an empty array without an error.

Written Explanation

The classic indexed loop

java
for (int i = 0; i < a.length; i++) {
    // a[i] is the current element
}

Read the three parts as a checklist for valid indices:

  1. Start at 0, the first valid index.
  2. Keep going while i < a.length. The last valid index is length - 1, so the loop must stop before length.
  3. Step by i++ to move one locker at a time.

If you write i <= a.length, the body runs once more with i == a.length, and a[i] throws ArrayIndexOutOfBoundsException. This single character is the most common array bug there is.

You can also count down, or visit only part of an array:

java
for (int i = a.length - 1; i >= 0; i--) { ... }   // backwards: last index down to 0
for (int i = 1; i < a.length; i++) { ... }        // skip the first element

The enhanced for loop

When you want each value and do not care about its position, Java has a shorter form (the language specification calls it the enhanced for statement):

java
for (int s : scores) {
    // s is the current element
}

Read the colon as "in": "for each int s in scores". The loop visits every element from the first to the last, in order. There is no index to get wrong, so no off-by-one is possible. It works the same way for String[], double[], and every other array type.

Which loop should I use?

You need...Use
Every value, nothing else (sum, count, print)Enhanced for
The position (print 0: ..., find where something is)Indexed for
To change elements (a[i] = ...)Indexed for
Backwards, every second element, or part of the arrayIndexed for
Two arrays side by side (same index in each)Indexed for

The enhanced loop is the right default for reading. Reach for the indexed loop when the table says so.

A trap: the loop variable is a copy

In for (int s : scores), the variable s is a copy of the current element. Assigning to s changes the copy and leaves the array alone:

java
for (int p : prices) {
    p = p * 2;     // changes only p; prices is unchanged
}

To modify an array, use the indexed loop and write prices[i] = .... The same holds for String[]: n = n.toUpperCase() reassigns the local variable only. (Strings cannot be modified at all, as BEG-009 explained.)

Staying inside the bounds

Before you run a loop, ask one question about every array access: is the index at least 0 and at most length - 1? Check the first and the last iteration by hand. When the body reads a neighbour, the range must shrink:

java
for (int i = 0; i < a.length - 1; i++) {
    // a[i] and a[i + 1] are both valid here
}

The loop stops at length - 2, so i + 1 is at most length - 1.

The empty array

new int[0] or {} is a legal array of length 0. A loop over it runs zero times, with no error, because 0 < 0 is false from the start. Code that uses a[0] directly (such as starting a "maximum" at a[0]) does crash on an empty array, so test a.length == 0 first when empty input is possible.

Examples

Example 1: two loops over the same array (simple)

java
public class Ex1 {
    public static void main(String[] args) {
        int[] scores = {80, 90, 70};
        int total = 0;
        for (int s : scores) {
            total += s;
        }
        System.out.println("Total: " + total);
        for (int i = scores.length - 1; i >= 0; i--) {
            System.out.println(i + ": " + scores[i]);
        }
    }
}

Output (compiled and run with JDK 21):

text
Total: 240
2: 70
1: 90
0: 80

The sum needs only values, so enhanced for fits. Printing positions in reverse order needs the index, so the indexed loop fits.

Example 2: the copy trap (practical)

java
public class Ex2 {
    public static void main(String[] args) {
        int[] prices = {10, 20, 30};
        for (int p : prices) {
            p = p * 2;
        }
        System.out.println(prices[0] + " " + prices[1] + " " + prices[2]);
        for (int i = 0; i < prices.length; i++) {
            prices[i] = prices[i] * 2;
        }
        System.out.println(prices[0] + " " + prices[1] + " " + prices[2]);
        String[] names = {"Ana", "Omar", "Lina"};
        for (String n : names) {
            n = n.toUpperCase();
        }
        System.out.println(names[0]);
    }
}

Output:

text
10 20 30
20 40 60
Ana

The first loop doubled only its own copy p. The second loop wrote into the array. The third loop left names unchanged, so the first name is still Ana.

Example 3: neighbours and the off-by-one (realistic)

A common check on sorted-looking data, such as sensor readings, is "how many times is a value equal to the one after it?"

java
public class Ex3 {
    static int countPairs(int[] a) {
        int equalNeighbours = 0;
        for (int i = 0; i < a.length - 1; i++) {
            if (a[i] == a[i + 1]) {
                equalNeighbours++;
            }
        }
        return equalNeighbours;
    }

    public static void main(String[] args) {
        System.out.println(countPairs(new int[]{1, 1, 2, 2, 2, 3}));
        System.out.println(countPairs(new int[]{5}));
        System.out.println(countPairs(new int[]{}));
        int[] data = {4, 5, 6};
        for (int i = 0; i <= data.length; i++) {
            System.out.println(data[i]);
        }
    }
}

Output:

text
3
0
0
4
5
6
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
	at Ex3.main(Ex3.java:18)

The bound a.length - 1 keeps a[i + 1] valid. For a one-element and a zero-element array the loop simply runs zero times; the empty array works because 0 - 1 is -1 and 0 < -1 is false. The last loop shows the planted bug: <= lets i reach 3, and the trace points at line 18 and says "Index 3 out of bounds for length 3". The three printed values 4, 5, 6 come out before the crash.

Backend Insight

Backend code spends most of its time in loops over lists: validating every field of a request, totalling every line of an invoice, writing every record of a report. Two habits scale well:

  • Prefer the loop that cannot go wrong. If you do not need the index, the enhanced for removes a whole class of bugs. Production code is full of bounds errors that a simpler loop would have avoided.
  • Treat empty as a normal input. A search that returns zero rows, an empty upload, or a filter that matches nothing all produce empty arrays or lists. Code that assumes at least one element works in testing and fails on the first quiet day in production.

Common Mistakes

Mistake 1: <= instead of <

  • Incorrect: for (int i = 0; i <= a.length; i++)
  • Correct: for (int i = 0; i < a.length; i++)

With <= the last pass uses index length, which does not exist.

Mistake 2: Trying to change an array through the enhanced-for variable

for (int p : prices) p = p * 2; does nothing to prices. Use prices[i] = prices[i] * 2; inside an indexed loop.

Mistake 3: Reading the neighbour without shrinking the range

for (int i = 0; i < a.length; i++) if (a[i] == a[i + 1]) fails on the last pass. Stop at a.length - 1.

Mistake 4: Starting a maximum at 0 or at a[0] without thinking

Starting at 0 gives a wrong answer when every value is negative. Starting at a[0] crashes when the array is empty. Start at a[0] and guard the empty case first.

Mistake 5: Changing the array's length inside the loop and expecting the bound to move

An array's length never changes, so there is nothing to track. If you think you need "the current size", you probably need a counter variable separate from a.length.

Exercises

Try each exercise yourself before opening the solutions.

Level A: Foundation

A1. Print every element of String[] days = {"Mon", "Tue", "Wed"} on its own line using the enhanced for.

Show solution A1

A1.

java
for (String d : days) {
    System.out.println(d);
}

A2. Which loop (indexed or enhanced) fits each task? (a) Add up all values. (b) Print index: value pairs. (c) Set every element to 0.

Show solution A2

A2. (a) Enhanced. (b) Indexed, because it needs the position. (c) Indexed, because it writes elements.

A3. What is wrong with for (int i = 1; i <= a.length; i++) System.out.println(a[i]); if the intention is to print all elements?

Show solution A3

A3. It starts at 1 and skips the first element, and <= lets i reach a.length, which throws ArrayIndexOutOfBoundsException. The correct loop is for (int i = 0; i < a.length; i++).

Level B: Application

B1. Write a loop that adds only the even numbers of an int[] a.

Show solution B1

B1.

java
int sum = 0;
for (int x : a) {
    if (x % 2 == 0) {
        sum += x;
    }
}

B2. Print the elements of a from last to first.

Show solution B2

B2.

java
for (int i = a.length - 1; i >= 0; i--) {
    System.out.println(a[i]);
}

B3. What does this print, and why?

java
int[] a = {1, 2, 3};
for (int x : a) {
    x = x + 10;
}
System.out.println(a[0] + a[1] + a[2]);
Show solution B3

B3. It prints 6. The variable x is a copy of each element, so adding 10 to x never reaches the array, and the sum is 1 + 2 + 3.

Level C: Challenge

C1. Write static int largest(int[] a) that returns the largest element, or -1 if the array is empty. Explain why -1 is risky here and name a better design in one sentence.

Show solution C1

C1.

java
static int largest(int[] a) {
    if (a.length == 0) {
        return -1;
    }
    int best = a[0];
    for (int x : a) {
        if (x > best) {
            best = x;
        }
    }
    return best;
}

-1 is risky because it can also be a real largest value (all numbers negative), so the caller cannot tell the cases apart. A better design is to check for emptiness before calling, or to signal "no value" in a way that cannot be mistaken for data (you will meet options for that later in the course).

C2. Write static int rises(int[] a) that counts the positions where an element is greater than the one before it. For {3, 5, 4, 6, 6, 9} the answer is 3.

Show solution C2

C2.

java
static int rises(int[] a) {
    int count = 0;
    for (int i = 1; i < a.length; i++) {
        if (a[i] > a[i - 1]) {
            count++;
        }
    }
    return count;
}

Starting at 1 keeps a[i - 1] valid. The pairs (3,5), (4,6), (6,9) rise, so the count is 3. An empty or one-element array gives 0.

Mini Challenge

Take an int[] of at least eight exam marks. Write a program, with a separate method for each task, that prints: the total, the largest mark and its index, how many marks are below the average, and the marks in reverse order. Test it with an array of one mark and with an empty array, and make sure neither run crashes: the empty case may print a message instead of results.

Check your work: every loop has bounds you verified for the first and last iteration, and you used the enhanced for wherever you did not need an index.

Summary & Next Lesson

Key takeaways

  • The indexed loop for (int i = 0; i < a.length; i++) visits every element; the bound is <, never <=.
  • The enhanced for (int x : a) gives you each value with no index, so it cannot go out of range.
  • The enhanced-for variable is a copy: assigning to it does not change the array.
  • Use the indexed loop when you need positions, need to write, or need a partial or reverse walk.
  • Before running a loop, check the first and last index it will use. An empty array makes a loop run zero times.

Next lesson

The next lesson, "Two-dimensional arrays", stacks rows of lockers into a grid and uses nested loops to visit every cell.

Self-check

  1. What is the first and the last index the loop for (int i = 0; i < a.length; i++) uses?
  2. When can you use the enhanced for, and when must you use the indexed loop?
  3. Does for (int x : a) x = 0; clear the array?
  4. How do you stop a[i + 1] from going out of range?
  5. What happens when a loop runs over an empty array?
Show answers
  1. 0 and a.length - 1.
  2. Enhanced for when you only read values; indexed loop when you need the position, want to write, or want a reverse or partial walk.
  3. No, x is a copy of each element.
  4. Stop the loop at i < a.length - 1.
  5. It runs zero times and nothing fails.

References

  • Oracle, Java Language Specification SE 21, chapter 10: Arrays. It supports: array indices run from 0 to length - 1, and accessing an index outside that range throws ArrayIndexOutOfBoundsException.
  • The enhanced for behaviour (the loop variable receives the element's value, not a link to its slot) and every output above were checked by compiling and running the code with JDK 21. I did not fetch the enhanced-for section of the specification itself, so the statement that it visits elements in index order from first to last comes from running the examples.

Practice

Apply this lesson with the module's lab, exercises and quiz.

Lab and exercises Quiz

Marking a lesson complete is optional and you can undo it any time. Your progress stays in this browser.

Continue to next lesson

Type to search levels, phases, modules and lessons.