Module 3 · Control Flow & Program Structure ⏱ 19 min

Arrays and Iteration

By the end of this lesson you will be able to:
  • Declare an array, access elements by zero-based index, and use the length field
  • Traverse an array with an indexed for loop and with the enhanced for-each, and choose between them
  • Predict why reassigning a for-each variable does not change the array, and avoid the bounds trap

Once your programs start handling real data, separate variables stop scaling. A class of three students fits neatly into s1, s2, s3; a class of three hundred does not. You need a single container that holds many values of the same type and lets you reach any one of them by position.

That container is an array. An array is a fixed-length, indexed sequence of values of one type — ten ints, four Strings, a hundred doubles. The length is chosen when the array is created and never changes afterwards; you cannot push a new score onto the end the way you can in Python or JavaScript. What you get in return is speed and simplicity: every element sits in one contiguous block, and reaching element i is a single, predictable calculation.

This lesson covers how to build an array, read and change its elements, and walk through all of them with a loop.

Creating and accessing an array

The shortest way to make an array is a literal — the values listed inside curly braces:

int[] scores = {12, 25, 8, 40};

int[] is the type (an array of int), and scores is the name. Elements are numbered from zero, so the first score is scores[0] and the last is scores[3] — never scores[4]. The expression inside the brackets is the index, and it can be any int expression, including a loop variable.

Every array carries its own length as scores.length. Notice it is a field, not a method: no parentheses. For a four-element array, length is 4, while the highest valid index is 3. That gap of exactly one is the root of the most common array bug.

Main.java — read the first element, the length, and the last element. Real, compiling Java.
public class Main {
    public static void main(String[] args) {
        int[] scores = {12, 25, 8, 40};
        System.out.println("first: " + scores[0]);
        System.out.println("count: " + scores.length);
        System.out.println("last: " + scores[scores.length - 1]);
    }
}
flowchart LR
  A0["index 0<br/>value 12"] --> A1["index 1<br/>value 25"] --> A2["index 2<br/>value 8"] --> A3["index 3<br/>value 40"]
  LEN["length is 4<br/>last index is 3"] -.-> A3
  style A0 fill:#3776ab,color:#fff
  style A3 fill:#b45309,color:#fff
An array is a row of numbered slots. Indices start at 0, so length 4 means the last valid index is 3.

The bounds trap

Access an index that does not exist and Java throws ArrayIndexOutOfBoundsException — immediately, with no chance to recover unless you catch it. The trap is the off-by-one: a loop that runs i <= scores.length instead of i < scores.length processes one index too many, because scores.length is one past the last valid slot.

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

The condition i < scores.length stops i at exactly the right place: it visits 0, 1, 2, 3 for a four-element array and never asks for scores[4]. Build this reflex now, because the same < versus <= decision haunts every indexed loop you will ever write.

Two ways to traverse: indexed and for-each

Java gives you two looping forms over an array. The indexed loop gives you the position as well as the value, which you need whenever you plan to change an element or compare neighbours. The enhanced for, often called for-each, hides the index entirely and just hands you each value in turn — ideal when you only want to read.

for (int s : scores) {   // for-each: read each value
    System.out.println(s);
}

Read the colon as in: for each int s in scores. You never touch an index, so you can never be off by one — and that safety is exactly the feature that sets up the next trap.

flowchart TD
  subgraph IDX["indexed for loop"]
    I1["i = 0"] --> I2{"i < length?"}
    I2 -->|"yes"| I3["use the element"]
    I3 --> I4["i++"]
    I4 --> I2
    I2 -->|"no"| I5["done"]
  end
  subgraph FE["enhanced for-each"]
    F1["take next element"] --> F2["x = that value"]
    F2 --> F3["use x"]
    F3 --> F1
  end
  style IDX fill:#3776ab,color:#fff
  style FE fill:#166534,color:#fff
An indexed loop gives you the position; a for-each gives you only the value, with no index to miscount.
Main.java — an indexed loop totals every price. Real, compiling Java.
public class Main {
    public static void main(String[] args) {
        int[] prices = {3, 7, 2, 8};
        int sum = 0;
        for (int i = 0; i < prices.length; i++) {
            sum = sum + prices[i];
        }
        System.out.println("total: " + sum);
    }
}
flowchart LR
  ARR["array element<br/>value 5"] -->|"copied into"| X["loop variable x = 5"]
  X -->|"multiply x by 10"| X2["x = 50<br/>but element still 5"]
  X2 -.->|"no write back"| ARR
  style X2 fill:#b45309,color:#fff
Reassigning the for-each variable x changes only the copy; the array element keeps its old value.

Changing an element

Because each slot has an index, updating a value is just an assignment with brackets: scores[2] = 99; replaces whatever lived at index 2 and leaves the other slots alone. The array stays the same object, the same length — only one cell changed. You can read that cell back immediately on the next line.

This is what makes arrays so predictable to reason about: a write touches exactly one position, and every other element is guaranteed unaffected. Contrast that with a single integer variable, where reusing the name for a new value erases the old one entirely. An array keeps every value alive and addressable, which is the whole reason to reach for one.

Default values and the fixed length

When you create an array with new int[5] instead of a literal, Java fills it with the default value for its type: 0 for whole numbers, false for booleans, null for objects. The slots exist immediately; they are simply zeroed until you write into them. A literal like {12, 25} sets the values and fixes the length in one stroke.

Arrays are mutable — you can overwrite any element through its index at any time — but their length is fixed. You cannot grow a four-slot array into a fifth slot; if you need that, Java's collections, which you will meet later, are the right tool. For a known, stable set of values, an array is exactly enough.

Exercise

Array basics. Predict the exact output (three lines) — remember indices start at 0.

public class Main {
    public static void main(String[] args) {
        int[] scores = {12, 25, 8, 40};
        System.out.println(scores[0]);
        System.out.println(scores.length);
        System.out.println(scores[3]);
    }
}
Exercise

Indexed traversal. Predict the exact output (two lines) — follow the sum and recall the first element.

public class Main {
    public static void main(String[] args) {
        int[] prices = {3, 7, 2, 8};
        int sum = 0;
        for (int i = 0; i < prices.length; i++) {
            sum = sum + prices[i];
        }
        System.out.println(sum);
        System.out.println(prices[0]);
    }
}
Exercise

An array was created with int[] a = {5, 10, 15, 20};. Which index holds the value 20, and what is a.length?

Exercise

The for-each trap. The loop tries to multiply every element by 10. Predict the exact output (three lines) — has the array actually changed?

public class Main {
    public static void main(String[] args) {
        int[] nums = {1, 2, 3};
        for (int x : nums) {
            x = x * 10;
        }
        System.out.println(nums[0]);
        System.out.println(nums[1]);
        System.out.println(nums[2]);
    }
}
Exercise

Write through the index. This loop really does modify the array. Predict the exact output (four lines) — track what each slot becomes.

public class Main {
    public static void main(String[] args) {
        int[] nums = {2, 4, 6, 8};
        for (int i = 0; i < nums.length; i++) {
            nums[i] = nums[i] + i;
        }
        System.out.println(nums[0]);
        System.out.println(nums[1]);
        System.out.println(nums[2]);
        System.out.println(nums[3]);
    }
}

Recap

  • An array is a fixed-length, zero-indexed container of one type. The first element sits at index 0, the last at length - 1.
  • arr.length is a field, not a method, and equals the number of slots — one more than the highest valid index.
  • Accessing a missing index throws ArrayIndexOutOfBoundsException. Loop with i < length, never i <= length.
  • The indexed loop gives you the position; for-each gives you only the value and is ideal for reading.
  • For-each hands you a copy of each element — reassigning it does not change the array. Write through the index to mutate a slot.

Next you will combine arrays with the loop patterns you already know to search, filter, and summarise real data.

Checkpoint quiz

Why does accessing arr[arr.length] throw an exception?

What is the effect of for (int x : arr) { x = x * 2; }?

Go deeper — technical resources